1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Microchip's LAN865x 10BASE-T1S MAC-PHY driver 4 * 5 * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com> 6 */ 7 8 #include <linux/module.h> 9 #include <linux/kernel.h> 10 #include <linux/phy.h> 11 #include <linux/oa_tc6.h> 12 13 #define DRV_NAME "lan8650" 14 15 /* MAC Network Control Register */ 16 #define LAN865X_REG_MAC_NET_CTL 0x00010000 17 #define MAC_NET_CTL_TXEN BIT(3) /* Transmit Enable */ 18 #define MAC_NET_CTL_RXEN BIT(2) /* Receive Enable */ 19 20 /* MAC Network Configuration Reg */ 21 #define LAN865X_REG_MAC_NET_CFG 0x00010001 22 #define MAC_NET_CFG_PROMISCUOUS_MODE BIT(4) 23 #define MAC_NET_CFG_MULTICAST_MODE BIT(6) 24 #define MAC_NET_CFG_UNICAST_MODE BIT(7) 25 26 /* MAC Hash Register Bottom */ 27 #define LAN865X_REG_MAC_L_HASH 0x00010020 28 /* MAC Hash Register Top */ 29 #define LAN865X_REG_MAC_H_HASH 0x00010021 30 /* MAC Specific Addr 1 Bottom Reg */ 31 #define LAN865X_REG_MAC_L_SADDR1 0x00010022 32 /* MAC Specific Addr 1 Top Reg */ 33 #define LAN865X_REG_MAC_H_SADDR1 0x00010023 34 35 struct lan865x_priv { 36 struct work_struct multicast_work; 37 struct net_device *netdev; 38 struct spi_device *spi; 39 struct oa_tc6 *tc6; 40 }; 41 42 static int lan865x_set_hw_macaddr_low_bytes(struct oa_tc6 *tc6, const u8 *mac) 43 { 44 u32 regval; 45 46 regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; 47 48 return oa_tc6_write_register(tc6, LAN865X_REG_MAC_L_SADDR1, regval); 49 } 50 51 static int lan865x_set_hw_macaddr(struct lan865x_priv *priv, const u8 *mac) 52 { 53 int restore_ret; 54 u32 regval; 55 int ret; 56 57 /* Configure MAC address low bytes */ 58 ret = lan865x_set_hw_macaddr_low_bytes(priv->tc6, mac); 59 if (ret) 60 return ret; 61 62 /* Prepare and configure MAC address high bytes */ 63 regval = (mac[5] << 8) | mac[4]; 64 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_SADDR1, 65 regval); 66 if (!ret) 67 return 0; 68 69 /* Restore the old MAC address low bytes from netdev if the new MAC 70 * address high bytes setting failed. 71 */ 72 restore_ret = lan865x_set_hw_macaddr_low_bytes(priv->tc6, 73 priv->netdev->dev_addr); 74 if (restore_ret) 75 return restore_ret; 76 77 return ret; 78 } 79 80 static const struct ethtool_ops lan865x_ethtool_ops = { 81 .get_link_ksettings = phy_ethtool_get_link_ksettings, 82 .set_link_ksettings = phy_ethtool_set_link_ksettings, 83 }; 84 85 static int lan865x_set_mac_address(struct net_device *netdev, void *addr) 86 { 87 struct lan865x_priv *priv = netdev_priv(netdev); 88 struct sockaddr *address = addr; 89 int ret; 90 91 ret = eth_prepare_mac_addr_change(netdev, addr); 92 if (ret < 0) 93 return ret; 94 95 if (ether_addr_equal(address->sa_data, netdev->dev_addr)) 96 return 0; 97 98 ret = lan865x_set_hw_macaddr(priv, address->sa_data); 99 if (ret) 100 return ret; 101 102 eth_commit_mac_addr_change(netdev, addr); 103 104 return 0; 105 } 106 107 static u32 get_address_bit(u8 addr[ETH_ALEN], u32 bit) 108 { 109 return ((addr[bit / 8]) >> (bit % 8)) & 1; 110 } 111 112 static u32 lan865x_hash(u8 addr[ETH_ALEN]) 113 { 114 u32 hash_index = 0; 115 116 for (int i = 0; i < 6; i++) { 117 u32 hash = 0; 118 119 for (int j = 0; j < 8; j++) 120 hash ^= get_address_bit(addr, (j * 6) + i); 121 122 hash_index |= (hash << i); 123 } 124 125 return hash_index; 126 } 127 128 static int lan865x_set_specific_multicast_addr(struct lan865x_priv *priv) 129 { 130 struct netdev_hw_addr *ha; 131 u32 hash_lo = 0; 132 u32 hash_hi = 0; 133 int ret; 134 135 netdev_for_each_mc_addr(ha, priv->netdev) { 136 u32 bit_num = lan865x_hash(ha->addr); 137 138 if (bit_num >= BIT(5)) 139 hash_hi |= (1 << (bit_num - BIT(5))); 140 else 141 hash_lo |= (1 << bit_num); 142 } 143 144 /* Enabling specific multicast addresses */ 145 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_HASH, hash_hi); 146 if (ret) { 147 netdev_err(priv->netdev, "Failed to write reg_hashh: %d\n", 148 ret); 149 return ret; 150 } 151 152 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_L_HASH, hash_lo); 153 if (ret) 154 netdev_err(priv->netdev, "Failed to write reg_hashl: %d\n", 155 ret); 156 157 return ret; 158 } 159 160 static int lan865x_set_all_multicast_addr(struct lan865x_priv *priv) 161 { 162 int ret; 163 164 /* Enabling all multicast addresses */ 165 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_HASH, 166 0xffffffff); 167 if (ret) { 168 netdev_err(priv->netdev, "Failed to write reg_hashh: %d\n", 169 ret); 170 return ret; 171 } 172 173 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_L_HASH, 174 0xffffffff); 175 if (ret) 176 netdev_err(priv->netdev, "Failed to write reg_hashl: %d\n", 177 ret); 178 179 return ret; 180 } 181 182 static int lan865x_clear_all_multicast_addr(struct lan865x_priv *priv) 183 { 184 int ret; 185 186 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_HASH, 0); 187 if (ret) { 188 netdev_err(priv->netdev, "Failed to write reg_hashh: %d\n", 189 ret); 190 return ret; 191 } 192 193 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_L_HASH, 0); 194 if (ret) 195 netdev_err(priv->netdev, "Failed to write reg_hashl: %d\n", 196 ret); 197 198 return ret; 199 } 200 201 static void lan865x_multicast_work_handler(struct work_struct *work) 202 { 203 struct lan865x_priv *priv = container_of(work, struct lan865x_priv, 204 multicast_work); 205 u32 regval = 0; 206 int ret; 207 208 if (priv->netdev->flags & IFF_PROMISC) { 209 /* Enabling promiscuous mode */ 210 regval |= MAC_NET_CFG_PROMISCUOUS_MODE; 211 regval &= (~MAC_NET_CFG_MULTICAST_MODE); 212 regval &= (~MAC_NET_CFG_UNICAST_MODE); 213 } else if (priv->netdev->flags & IFF_ALLMULTI) { 214 /* Enabling all multicast mode */ 215 if (lan865x_set_all_multicast_addr(priv)) 216 return; 217 218 regval &= (~MAC_NET_CFG_PROMISCUOUS_MODE); 219 regval |= MAC_NET_CFG_MULTICAST_MODE; 220 regval &= (~MAC_NET_CFG_UNICAST_MODE); 221 } else if (!netdev_mc_empty(priv->netdev)) { 222 /* Enabling specific multicast mode */ 223 if (lan865x_set_specific_multicast_addr(priv)) 224 return; 225 226 regval &= (~MAC_NET_CFG_PROMISCUOUS_MODE); 227 regval |= MAC_NET_CFG_MULTICAST_MODE; 228 regval &= (~MAC_NET_CFG_UNICAST_MODE); 229 } else { 230 /* Enabling local mac address only */ 231 if (lan865x_clear_all_multicast_addr(priv)) 232 return; 233 } 234 ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CFG, regval); 235 if (ret) 236 netdev_err(priv->netdev, "Failed to enable promiscuous/multicast/normal mode: %d\n", 237 ret); 238 } 239 240 static void lan865x_set_multicast_list(struct net_device *netdev) 241 { 242 struct lan865x_priv *priv = netdev_priv(netdev); 243 244 schedule_work(&priv->multicast_work); 245 } 246 247 static netdev_tx_t lan865x_send_packet(struct sk_buff *skb, 248 struct net_device *netdev) 249 { 250 struct lan865x_priv *priv = netdev_priv(netdev); 251 252 return oa_tc6_start_xmit(priv->tc6, skb); 253 } 254 255 static int lan865x_hw_disable(struct lan865x_priv *priv) 256 { 257 u32 regval; 258 259 if (oa_tc6_read_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, ®val)) 260 return -ENODEV; 261 262 regval &= ~(MAC_NET_CTL_TXEN | MAC_NET_CTL_RXEN); 263 264 if (oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, regval)) 265 return -ENODEV; 266 267 return 0; 268 } 269 270 static int lan865x_net_close(struct net_device *netdev) 271 { 272 struct lan865x_priv *priv = netdev_priv(netdev); 273 int ret; 274 275 netif_stop_queue(netdev); 276 phy_stop(netdev->phydev); 277 ret = lan865x_hw_disable(priv); 278 if (ret) { 279 netdev_err(netdev, "Failed to disable the hardware: %d\n", ret); 280 return ret; 281 } 282 283 return 0; 284 } 285 286 static int lan865x_hw_enable(struct lan865x_priv *priv) 287 { 288 u32 regval; 289 290 if (oa_tc6_read_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, ®val)) 291 return -ENODEV; 292 293 regval |= MAC_NET_CTL_TXEN | MAC_NET_CTL_RXEN; 294 295 if (oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, regval)) 296 return -ENODEV; 297 298 return 0; 299 } 300 301 static int lan865x_net_open(struct net_device *netdev) 302 { 303 struct lan865x_priv *priv = netdev_priv(netdev); 304 int ret; 305 306 ret = lan865x_hw_enable(priv); 307 if (ret) { 308 netdev_err(netdev, "Failed to enable hardware: %d\n", ret); 309 return ret; 310 } 311 312 phy_start(netdev->phydev); 313 314 return 0; 315 } 316 317 static const struct net_device_ops lan865x_netdev_ops = { 318 .ndo_open = lan865x_net_open, 319 .ndo_stop = lan865x_net_close, 320 .ndo_start_xmit = lan865x_send_packet, 321 .ndo_set_rx_mode = lan865x_set_multicast_list, 322 .ndo_set_mac_address = lan865x_set_mac_address, 323 }; 324 325 static int lan865x_probe(struct spi_device *spi) 326 { 327 struct net_device *netdev; 328 struct lan865x_priv *priv; 329 int ret; 330 331 netdev = alloc_etherdev(sizeof(struct lan865x_priv)); 332 if (!netdev) 333 return -ENOMEM; 334 335 priv = netdev_priv(netdev); 336 priv->netdev = netdev; 337 priv->spi = spi; 338 spi_set_drvdata(spi, priv); 339 INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler); 340 341 priv->tc6 = oa_tc6_init(spi, netdev); 342 if (!priv->tc6) { 343 ret = -ENODEV; 344 goto free_netdev; 345 } 346 347 /* As per the point s3 in the below errata, SPI receive Ethernet frame 348 * transfer may halt when starting the next frame in the same data block 349 * (chunk) as the end of a previous frame. The RFA field should be 350 * configured to 01b or 10b for proper operation. In these modes, only 351 * one receive Ethernet frame will be placed in a single data block. 352 * When the RFA field is written to 01b, received frames will be forced 353 * to only start in the first word of the data block payload (SWO=0). As 354 * recommended, enable zero align receive frame feature for proper 355 * operation. 356 * 357 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/Errata/LAN8650-1-Errata-80001075.pdf 358 */ 359 ret = oa_tc6_zero_align_receive_frame_enable(priv->tc6); 360 if (ret) { 361 dev_err(&spi->dev, "Failed to set ZARFE: %d\n", ret); 362 goto oa_tc6_exit; 363 } 364 365 /* Get the MAC address from the SPI device tree node */ 366 if (device_get_ethdev_address(&spi->dev, netdev)) 367 eth_hw_addr_random(netdev); 368 369 ret = lan865x_set_hw_macaddr(priv, netdev->dev_addr); 370 if (ret) { 371 dev_err(&spi->dev, "Failed to configure MAC: %d\n", ret); 372 goto oa_tc6_exit; 373 } 374 375 netdev->if_port = IF_PORT_10BASET; 376 netdev->irq = spi->irq; 377 netdev->netdev_ops = &lan865x_netdev_ops; 378 netdev->ethtool_ops = &lan865x_ethtool_ops; 379 380 ret = register_netdev(netdev); 381 if (ret) { 382 dev_err(&spi->dev, "Register netdev failed (ret = %d)", ret); 383 goto oa_tc6_exit; 384 } 385 386 return 0; 387 388 oa_tc6_exit: 389 oa_tc6_exit(priv->tc6); 390 free_netdev: 391 free_netdev(priv->netdev); 392 return ret; 393 } 394 395 static void lan865x_remove(struct spi_device *spi) 396 { 397 struct lan865x_priv *priv = spi_get_drvdata(spi); 398 399 cancel_work_sync(&priv->multicast_work); 400 unregister_netdev(priv->netdev); 401 oa_tc6_exit(priv->tc6); 402 free_netdev(priv->netdev); 403 } 404 405 static const struct spi_device_id spidev_spi_ids[] = { 406 { .name = "lan8650" }, 407 {}, 408 }; 409 410 static const struct of_device_id lan865x_dt_ids[] = { 411 { .compatible = "microchip,lan8650" }, 412 { /* Sentinel */ } 413 }; 414 MODULE_DEVICE_TABLE(of, lan865x_dt_ids); 415 416 static struct spi_driver lan865x_driver = { 417 .driver = { 418 .name = DRV_NAME, 419 .of_match_table = lan865x_dt_ids, 420 }, 421 .probe = lan865x_probe, 422 .remove = lan865x_remove, 423 .id_table = spidev_spi_ids, 424 }; 425 module_spi_driver(lan865x_driver); 426 427 MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver"); 428 MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>"); 429 MODULE_LICENSE("GPL"); 430