lan865x.c 11 KB

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