Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / ethernet / microchip / lan865x / lan865x.c
blobdd436bdff0f86ded067441401e672a361974b331
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Microchip's LAN865x 10BASE-T1S MAC-PHY driver
5 * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
6 */
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/phy.h>
11 #include <linux/oa_tc6.h>
13 #define DRV_NAME "lan8650"
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 */
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)
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
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;
42 static int lan865x_set_hw_macaddr_low_bytes(struct oa_tc6 *tc6, const u8 *mac)
44 u32 regval;
46 regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0];
48 return oa_tc6_write_register(tc6, LAN865X_REG_MAC_L_SADDR1, regval);
51 static int lan865x_set_hw_macaddr(struct lan865x_priv *priv, const u8 *mac)
53 int restore_ret;
54 u32 regval;
55 int ret;
57 /* Configure MAC address low bytes */
58 ret = lan865x_set_hw_macaddr_low_bytes(priv->tc6, mac);
59 if (ret)
60 return ret;
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;
69 /* Restore the old MAC address low bytes from netdev if the new MAC
70 * address high bytes setting failed.
72 restore_ret = lan865x_set_hw_macaddr_low_bytes(priv->tc6,
73 priv->netdev->dev_addr);
74 if (restore_ret)
75 return restore_ret;
77 return ret;
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,
85 static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
87 struct lan865x_priv *priv = netdev_priv(netdev);
88 struct sockaddr *address = addr;
89 int ret;
91 ret = eth_prepare_mac_addr_change(netdev, addr);
92 if (ret < 0)
93 return ret;
95 if (ether_addr_equal(address->sa_data, netdev->dev_addr))
96 return 0;
98 ret = lan865x_set_hw_macaddr(priv, address->sa_data);
99 if (ret)
100 return ret;
102 eth_commit_mac_addr_change(netdev, addr);
104 return 0;
107 static u32 get_address_bit(u8 addr[ETH_ALEN], u32 bit)
109 return ((addr[bit / 8]) >> (bit % 8)) & 1;
112 static u32 lan865x_hash(u8 addr[ETH_ALEN])
114 u32 hash_index = 0;
116 for (int i = 0; i < 6; i++) {
117 u32 hash = 0;
119 for (int j = 0; j < 8; j++)
120 hash ^= get_address_bit(addr, (j * 6) + i);
122 hash_index |= (hash << i);
125 return hash_index;
128 static int lan865x_set_specific_multicast_addr(struct lan865x_priv *priv)
130 struct netdev_hw_addr *ha;
131 u32 hash_lo = 0;
132 u32 hash_hi = 0;
133 int ret;
135 netdev_for_each_mc_addr(ha, priv->netdev) {
136 u32 bit_num = lan865x_hash(ha->addr);
138 if (bit_num >= BIT(5))
139 hash_hi |= (1 << (bit_num - BIT(5)));
140 else
141 hash_lo |= (1 << bit_num);
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;
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);
157 return ret;
160 static int lan865x_set_all_multicast_addr(struct lan865x_priv *priv)
162 int ret;
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;
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);
179 return ret;
182 static int lan865x_clear_all_multicast_addr(struct lan865x_priv *priv)
184 int ret;
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;
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);
198 return ret;
201 static void lan865x_multicast_work_handler(struct work_struct *work)
203 struct lan865x_priv *priv = container_of(work, struct lan865x_priv,
204 multicast_work);
205 u32 regval = 0;
206 int ret;
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;
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;
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;
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);
240 static void lan865x_set_multicast_list(struct net_device *netdev)
242 struct lan865x_priv *priv = netdev_priv(netdev);
244 schedule_work(&priv->multicast_work);
247 static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
248 struct net_device *netdev)
250 struct lan865x_priv *priv = netdev_priv(netdev);
252 return oa_tc6_start_xmit(priv->tc6, skb);
255 static int lan865x_hw_disable(struct lan865x_priv *priv)
257 u32 regval;
259 if (oa_tc6_read_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, &regval))
260 return -ENODEV;
262 regval &= ~(MAC_NET_CTL_TXEN | MAC_NET_CTL_RXEN);
264 if (oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, regval))
265 return -ENODEV;
267 return 0;
270 static int lan865x_net_close(struct net_device *netdev)
272 struct lan865x_priv *priv = netdev_priv(netdev);
273 int ret;
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;
283 return 0;
286 static int lan865x_hw_enable(struct lan865x_priv *priv)
288 u32 regval;
290 if (oa_tc6_read_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, &regval))
291 return -ENODEV;
293 regval |= MAC_NET_CTL_TXEN | MAC_NET_CTL_RXEN;
295 if (oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, regval))
296 return -ENODEV;
298 return 0;
301 static int lan865x_net_open(struct net_device *netdev)
303 struct lan865x_priv *priv = netdev_priv(netdev);
304 int ret;
306 ret = lan865x_hw_enable(priv);
307 if (ret) {
308 netdev_err(netdev, "Failed to enable hardware: %d\n", ret);
309 return ret;
312 phy_start(netdev->phydev);
314 return 0;
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,
325 static int lan865x_probe(struct spi_device *spi)
327 struct net_device *netdev;
328 struct lan865x_priv *priv;
329 int ret;
331 netdev = alloc_etherdev(sizeof(struct lan865x_priv));
332 if (!netdev)
333 return -ENOMEM;
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);
341 priv->tc6 = oa_tc6_init(spi, netdev);
342 if (!priv->tc6) {
343 ret = -ENODEV;
344 goto free_netdev;
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.
357 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/Errata/LAN8650-1-Errata-80001075.pdf
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;
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);
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;
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;
380 ret = register_netdev(netdev);
381 if (ret) {
382 dev_err(&spi->dev, "Register netdev failed (ret = %d)", ret);
383 goto oa_tc6_exit;
386 return 0;
388 oa_tc6_exit:
389 oa_tc6_exit(priv->tc6);
390 free_netdev:
391 free_netdev(priv->netdev);
392 return ret;
395 static void lan865x_remove(struct spi_device *spi)
397 struct lan865x_priv *priv = spi_get_drvdata(spi);
399 cancel_work_sync(&priv->multicast_work);
400 unregister_netdev(priv->netdev);
401 oa_tc6_exit(priv->tc6);
402 free_netdev(priv->netdev);
405 static const struct spi_device_id spidev_spi_ids[] = {
406 { .name = "lan8650" },
410 static const struct of_device_id lan865x_dt_ids[] = {
411 { .compatible = "microchip,lan8650" },
412 { /* Sentinel */ }
414 MODULE_DEVICE_TABLE(of, lan865x_dt_ids);
416 static struct spi_driver lan865x_driver = {
417 .driver = {
418 .name = DRV_NAME,
419 .of_match_table = lan865x_dt_ids,
421 .probe = lan865x_probe,
422 .remove = lan865x_remove,
423 .id_table = spidev_spi_ids,
425 module_spi_driver(lan865x_driver);
427 MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver");
428 MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>");
429 MODULE_LICENSE("GPL");