1 // SPDX-License-Identifier: GPL-2.0+
3 * Microchip's LAN865x 10BASE-T1S MAC-PHY driver
5 * Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
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
36 struct work_struct multicast_work
;
37 struct net_device
*netdev
;
38 struct spi_device
*spi
;
42 static int lan865x_set_hw_macaddr_low_bytes(struct oa_tc6
*tc6
, const u8
*mac
)
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
)
57 /* Configure MAC address low bytes */
58 ret
= lan865x_set_hw_macaddr_low_bytes(priv
->tc6
, mac
);
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
,
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
);
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
;
91 ret
= eth_prepare_mac_addr_change(netdev
, addr
);
95 if (ether_addr_equal(address
->sa_data
, netdev
->dev_addr
))
98 ret
= lan865x_set_hw_macaddr(priv
, address
->sa_data
);
102 eth_commit_mac_addr_change(netdev
, addr
);
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
])
116 for (int i
= 0; i
< 6; i
++) {
119 for (int j
= 0; j
< 8; j
++)
120 hash
^= get_address_bit(addr
, (j
* 6) + i
);
122 hash_index
|= (hash
<< i
);
128 static int lan865x_set_specific_multicast_addr(struct lan865x_priv
*priv
)
130 struct netdev_hw_addr
*ha
;
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)));
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
);
147 netdev_err(priv
->netdev
, "Failed to write reg_hashh: %d\n",
152 ret
= oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_L_HASH
, hash_lo
);
154 netdev_err(priv
->netdev
, "Failed to write reg_hashl: %d\n",
160 static int lan865x_set_all_multicast_addr(struct lan865x_priv
*priv
)
164 /* Enabling all multicast addresses */
165 ret
= oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_H_HASH
,
168 netdev_err(priv
->netdev
, "Failed to write reg_hashh: %d\n",
173 ret
= oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_L_HASH
,
176 netdev_err(priv
->netdev
, "Failed to write reg_hashl: %d\n",
182 static int lan865x_clear_all_multicast_addr(struct lan865x_priv
*priv
)
186 ret
= oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_H_HASH
, 0);
188 netdev_err(priv
->netdev
, "Failed to write reg_hashh: %d\n",
193 ret
= oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_L_HASH
, 0);
195 netdev_err(priv
->netdev
, "Failed to write reg_hashl: %d\n",
201 static void lan865x_multicast_work_handler(struct work_struct
*work
)
203 struct lan865x_priv
*priv
= container_of(work
, struct lan865x_priv
,
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
))
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
))
226 regval
&= (~MAC_NET_CFG_PROMISCUOUS_MODE
);
227 regval
|= MAC_NET_CFG_MULTICAST_MODE
;
228 regval
&= (~MAC_NET_CFG_UNICAST_MODE
);
230 /* Enabling local mac address only */
231 if (lan865x_clear_all_multicast_addr(priv
))
234 ret
= oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_NET_CFG
, regval
);
236 netdev_err(priv
->netdev
, "Failed to enable promiscuous/multicast/normal mode: %d\n",
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
)
259 if (oa_tc6_read_register(priv
->tc6
, LAN865X_REG_MAC_NET_CTL
, ®val
))
262 regval
&= ~(MAC_NET_CTL_TXEN
| MAC_NET_CTL_RXEN
);
264 if (oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_NET_CTL
, regval
))
270 static int lan865x_net_close(struct net_device
*netdev
)
272 struct lan865x_priv
*priv
= netdev_priv(netdev
);
275 netif_stop_queue(netdev
);
276 phy_stop(netdev
->phydev
);
277 ret
= lan865x_hw_disable(priv
);
279 netdev_err(netdev
, "Failed to disable the hardware: %d\n", ret
);
286 static int lan865x_hw_enable(struct lan865x_priv
*priv
)
290 if (oa_tc6_read_register(priv
->tc6
, LAN865X_REG_MAC_NET_CTL
, ®val
))
293 regval
|= MAC_NET_CTL_TXEN
| MAC_NET_CTL_RXEN
;
295 if (oa_tc6_write_register(priv
->tc6
, LAN865X_REG_MAC_NET_CTL
, regval
))
301 static int lan865x_net_open(struct net_device
*netdev
)
303 struct lan865x_priv
*priv
= netdev_priv(netdev
);
306 ret
= lan865x_hw_enable(priv
);
308 netdev_err(netdev
, "Failed to enable hardware: %d\n", ret
);
312 phy_start(netdev
->phydev
);
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
;
331 netdev
= alloc_etherdev(sizeof(struct lan865x_priv
));
335 priv
= netdev_priv(netdev
);
336 priv
->netdev
= netdev
;
338 spi_set_drvdata(spi
, priv
);
339 INIT_WORK(&priv
->multicast_work
, lan865x_multicast_work_handler
);
341 priv
->tc6
= oa_tc6_init(spi
, 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
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
);
361 dev_err(&spi
->dev
, "Failed to set ZARFE: %d\n", ret
);
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
);
371 dev_err(&spi
->dev
, "Failed to configure MAC: %d\n", ret
);
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
);
382 dev_err(&spi
->dev
, "Register netdev failed (ret = %d)", ret
);
389 oa_tc6_exit(priv
->tc6
);
391 free_netdev(priv
->netdev
);
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" },
414 MODULE_DEVICE_TABLE(of
, lan865x_dt_ids
);
416 static struct spi_driver lan865x_driver
= {
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");