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