1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright Sunplus Technology Co., Ltd. |
3 | * All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/platform_device.h> |
7 | #include <linux/nvmem-consumer.h> |
8 | #include <linux/etherdevice.h> |
9 | #include <linux/netdevice.h> |
10 | #include <linux/spinlock.h> |
11 | #include <linux/of_net.h> |
12 | #include <linux/reset.h> |
13 | #include <linux/clk.h> |
14 | #include <linux/of.h> |
15 | |
16 | #include "spl2sw_register.h" |
17 | #include "spl2sw_define.h" |
18 | #include "spl2sw_desc.h" |
19 | #include "spl2sw_mdio.h" |
20 | #include "spl2sw_phy.h" |
21 | #include "spl2sw_int.h" |
22 | #include "spl2sw_mac.h" |
23 | |
24 | /* net device operations */ |
25 | static int spl2sw_ethernet_open(struct net_device *ndev) |
26 | { |
27 | struct spl2sw_mac *mac = netdev_priv(dev: ndev); |
28 | struct spl2sw_common *comm = mac->comm; |
29 | u32 mask; |
30 | |
31 | netdev_dbg(ndev, "Open port = %x\n" , mac->lan_port); |
32 | |
33 | comm->enable |= mac->lan_port; |
34 | |
35 | spl2sw_mac_hw_start(comm); |
36 | |
37 | /* Enable TX and RX interrupts */ |
38 | mask = readl(addr: comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); |
39 | mask &= ~(MAC_INT_TX | MAC_INT_RX); |
40 | writel(val: mask, addr: comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); |
41 | |
42 | phy_start(phydev: ndev->phydev); |
43 | |
44 | netif_start_queue(dev: ndev); |
45 | |
46 | return 0; |
47 | } |
48 | |
49 | static int spl2sw_ethernet_stop(struct net_device *ndev) |
50 | { |
51 | struct spl2sw_mac *mac = netdev_priv(dev: ndev); |
52 | struct spl2sw_common *comm = mac->comm; |
53 | |
54 | netif_stop_queue(dev: ndev); |
55 | |
56 | comm->enable &= ~mac->lan_port; |
57 | |
58 | phy_stop(phydev: ndev->phydev); |
59 | |
60 | spl2sw_mac_hw_stop(comm); |
61 | |
62 | return 0; |
63 | } |
64 | |
65 | static netdev_tx_t spl2sw_ethernet_start_xmit(struct sk_buff *skb, |
66 | struct net_device *ndev) |
67 | { |
68 | struct spl2sw_mac *mac = netdev_priv(dev: ndev); |
69 | struct spl2sw_common *comm = mac->comm; |
70 | struct spl2sw_skb_info *skbinfo; |
71 | struct spl2sw_mac_desc *txdesc; |
72 | unsigned long flags; |
73 | u32 mapping; |
74 | u32 tx_pos; |
75 | u32 cmd1; |
76 | u32 cmd2; |
77 | |
78 | if (unlikely(comm->tx_desc_full == 1)) { |
79 | /* No TX descriptors left. Wait for tx interrupt. */ |
80 | netdev_dbg(ndev, "TX descriptor queue full when xmit!\n" ); |
81 | return NETDEV_TX_BUSY; |
82 | } |
83 | |
84 | /* If skb size is shorter than ETH_ZLEN (60), pad it with 0. */ |
85 | if (unlikely(skb->len < ETH_ZLEN)) { |
86 | if (skb_padto(skb, ETH_ZLEN)) |
87 | return NETDEV_TX_OK; |
88 | |
89 | skb_put(skb, ETH_ZLEN - skb->len); |
90 | } |
91 | |
92 | mapping = dma_map_single(&comm->pdev->dev, skb->data, |
93 | skb->len, DMA_TO_DEVICE); |
94 | if (dma_mapping_error(dev: &comm->pdev->dev, dma_addr: mapping)) { |
95 | ndev->stats.tx_errors++; |
96 | dev_kfree_skb(skb); |
97 | return NETDEV_TX_OK; |
98 | } |
99 | |
100 | spin_lock_irqsave(&comm->tx_lock, flags); |
101 | |
102 | tx_pos = comm->tx_pos; |
103 | txdesc = &comm->tx_desc[tx_pos]; |
104 | skbinfo = &comm->tx_temp_skb_info[tx_pos]; |
105 | skbinfo->mapping = mapping; |
106 | skbinfo->len = skb->len; |
107 | skbinfo->skb = skb; |
108 | |
109 | /* Set up a TX descriptor */ |
110 | cmd1 = TXD_OWN | TXD_SOP | TXD_EOP | (mac->to_vlan << 12) | |
111 | (skb->len & TXD_PKT_LEN); |
112 | cmd2 = skb->len & TXD_BUF_LEN1; |
113 | |
114 | if (tx_pos == (TX_DESC_NUM - 1)) |
115 | cmd2 |= TXD_EOR; |
116 | |
117 | txdesc->addr1 = skbinfo->mapping; |
118 | txdesc->cmd2 = cmd2; |
119 | wmb(); /* Set TXD_OWN after other fields are effective. */ |
120 | txdesc->cmd1 = cmd1; |
121 | |
122 | /* Move tx_pos to next position */ |
123 | tx_pos = ((tx_pos + 1) == TX_DESC_NUM) ? 0 : tx_pos + 1; |
124 | |
125 | if (unlikely(tx_pos == comm->tx_done_pos)) { |
126 | netif_stop_queue(dev: ndev); |
127 | comm->tx_desc_full = 1; |
128 | } |
129 | comm->tx_pos = tx_pos; |
130 | wmb(); /* make sure settings are effective. */ |
131 | |
132 | /* Trigger mac to transmit */ |
133 | writel(MAC_TRIG_L_SOC0, addr: comm->l2sw_reg_base + L2SW_CPU_TX_TRIG); |
134 | |
135 | spin_unlock_irqrestore(lock: &comm->tx_lock, flags); |
136 | return NETDEV_TX_OK; |
137 | } |
138 | |
139 | static void spl2sw_ethernet_set_rx_mode(struct net_device *ndev) |
140 | { |
141 | struct spl2sw_mac *mac = netdev_priv(dev: ndev); |
142 | |
143 | spl2sw_mac_rx_mode_set(mac); |
144 | } |
145 | |
146 | static int spl2sw_ethernet_set_mac_address(struct net_device *ndev, void *addr) |
147 | { |
148 | struct spl2sw_mac *mac = netdev_priv(dev: ndev); |
149 | int err; |
150 | |
151 | err = eth_mac_addr(dev: ndev, p: addr); |
152 | if (err) |
153 | return err; |
154 | |
155 | /* Delete the old MAC address */ |
156 | netdev_dbg(ndev, "Old Ethernet (MAC) address = %pM\n" , mac->mac_addr); |
157 | if (is_valid_ether_addr(addr: mac->mac_addr)) { |
158 | err = spl2sw_mac_addr_del(mac); |
159 | if (err) |
160 | return err; |
161 | } |
162 | |
163 | /* Set the MAC address */ |
164 | ether_addr_copy(dst: mac->mac_addr, src: ndev->dev_addr); |
165 | return spl2sw_mac_addr_add(mac); |
166 | } |
167 | |
168 | static void spl2sw_ethernet_tx_timeout(struct net_device *ndev, unsigned int txqueue) |
169 | { |
170 | struct spl2sw_mac *mac = netdev_priv(dev: ndev); |
171 | struct spl2sw_common *comm = mac->comm; |
172 | unsigned long flags; |
173 | int i; |
174 | |
175 | netdev_err(dev: ndev, format: "TX timed out!\n" ); |
176 | ndev->stats.tx_errors++; |
177 | |
178 | spin_lock_irqsave(&comm->tx_lock, flags); |
179 | |
180 | for (i = 0; i < MAX_NETDEV_NUM; i++) |
181 | if (comm->ndev[i]) |
182 | netif_stop_queue(dev: comm->ndev[i]); |
183 | |
184 | spl2sw_mac_soft_reset(comm); |
185 | |
186 | /* Accept TX packets again. */ |
187 | for (i = 0; i < MAX_NETDEV_NUM; i++) |
188 | if (comm->ndev[i]) { |
189 | netif_trans_update(dev: comm->ndev[i]); |
190 | netif_wake_queue(dev: comm->ndev[i]); |
191 | } |
192 | |
193 | spin_unlock_irqrestore(lock: &comm->tx_lock, flags); |
194 | } |
195 | |
196 | static const struct net_device_ops netdev_ops = { |
197 | .ndo_open = spl2sw_ethernet_open, |
198 | .ndo_stop = spl2sw_ethernet_stop, |
199 | .ndo_start_xmit = spl2sw_ethernet_start_xmit, |
200 | .ndo_set_rx_mode = spl2sw_ethernet_set_rx_mode, |
201 | .ndo_set_mac_address = spl2sw_ethernet_set_mac_address, |
202 | .ndo_do_ioctl = phy_do_ioctl, |
203 | .ndo_tx_timeout = spl2sw_ethernet_tx_timeout, |
204 | }; |
205 | |
206 | static void spl2sw_check_mac_vendor_id_and_convert(u8 *mac_addr) |
207 | { |
208 | /* Byte order of MAC address of some samples are reversed. |
209 | * Check vendor id and convert byte order if it is wrong. |
210 | * OUI of Sunplus: fc:4b:bc |
211 | */ |
212 | if (mac_addr[5] == 0xfc && mac_addr[4] == 0x4b && mac_addr[3] == 0xbc && |
213 | (mac_addr[0] != 0xfc || mac_addr[1] != 0x4b || mac_addr[2] != 0xbc)) { |
214 | |
215 | swap(mac_addr[0], mac_addr[5]); |
216 | swap(mac_addr[1], mac_addr[4]); |
217 | swap(mac_addr[2], mac_addr[3]); |
218 | } |
219 | } |
220 | |
221 | static int spl2sw_nvmem_get_mac_address(struct device *dev, struct device_node *np, |
222 | void *addrbuf) |
223 | { |
224 | struct nvmem_cell *cell; |
225 | ssize_t len; |
226 | u8 *mac; |
227 | |
228 | /* Get nvmem cell of mac-address from dts. */ |
229 | cell = of_nvmem_cell_get(np, id: "mac-address" ); |
230 | if (IS_ERR(ptr: cell)) |
231 | return PTR_ERR(ptr: cell); |
232 | |
233 | /* Read mac address from nvmem cell. */ |
234 | mac = nvmem_cell_read(cell, len: &len); |
235 | nvmem_cell_put(cell); |
236 | if (IS_ERR(ptr: mac)) |
237 | return PTR_ERR(ptr: mac); |
238 | |
239 | if (len != ETH_ALEN) { |
240 | kfree(objp: mac); |
241 | dev_info(dev, "Invalid length of mac address in nvmem!\n" ); |
242 | return -EINVAL; |
243 | } |
244 | |
245 | /* Byte order of some samples are reversed. |
246 | * Convert byte order here. |
247 | */ |
248 | spl2sw_check_mac_vendor_id_and_convert(mac_addr: mac); |
249 | |
250 | /* Check if mac address is valid */ |
251 | if (!is_valid_ether_addr(addr: mac)) { |
252 | dev_info(dev, "Invalid mac address in nvmem (%pM)!\n" , mac); |
253 | kfree(objp: mac); |
254 | return -EINVAL; |
255 | } |
256 | |
257 | ether_addr_copy(dst: addrbuf, src: mac); |
258 | kfree(objp: mac); |
259 | return 0; |
260 | } |
261 | |
262 | static u32 spl2sw_init_netdev(struct platform_device *pdev, u8 *mac_addr, |
263 | struct net_device **r_ndev) |
264 | { |
265 | struct net_device *ndev; |
266 | struct spl2sw_mac *mac; |
267 | int ret; |
268 | |
269 | /* Allocate the devices, and also allocate spl2sw_mac, |
270 | * we can get it by netdev_priv(). |
271 | */ |
272 | ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*mac)); |
273 | if (!ndev) { |
274 | *r_ndev = NULL; |
275 | return -ENOMEM; |
276 | } |
277 | SET_NETDEV_DEV(ndev, &pdev->dev); |
278 | ndev->netdev_ops = &netdev_ops; |
279 | mac = netdev_priv(dev: ndev); |
280 | mac->ndev = ndev; |
281 | ether_addr_copy(dst: mac->mac_addr, src: mac_addr); |
282 | |
283 | eth_hw_addr_set(dev: ndev, addr: mac_addr); |
284 | dev_info(&pdev->dev, "Ethernet (MAC) address = %pM\n" , mac_addr); |
285 | |
286 | ret = register_netdev(dev: ndev); |
287 | if (ret) { |
288 | dev_err(&pdev->dev, "Failed to register net device \"%s\"!\n" , |
289 | ndev->name); |
290 | *r_ndev = NULL; |
291 | return ret; |
292 | } |
293 | netdev_dbg(ndev, "Registered net device \"%s\" successfully.\n" , ndev->name); |
294 | |
295 | *r_ndev = ndev; |
296 | return 0; |
297 | } |
298 | |
299 | static struct device_node *spl2sw_get_eth_child_node(struct device_node *ether_np, int id) |
300 | { |
301 | struct device_node *port_np; |
302 | int port_id; |
303 | |
304 | for_each_child_of_node(ether_np, port_np) { |
305 | /* It is not a 'port' node, continue. */ |
306 | if (strcmp(port_np->name, "port" )) |
307 | continue; |
308 | |
309 | if (of_property_read_u32(np: port_np, propname: "reg" , out_value: &port_id) < 0) |
310 | continue; |
311 | |
312 | if (port_id == id) |
313 | return port_np; |
314 | } |
315 | |
316 | /* Not found! */ |
317 | return NULL; |
318 | } |
319 | |
320 | static int spl2sw_probe(struct platform_device *pdev) |
321 | { |
322 | struct device_node *eth_ports_np; |
323 | struct device_node *port_np; |
324 | struct spl2sw_common *comm; |
325 | struct device_node *phy_np; |
326 | phy_interface_t phy_mode; |
327 | struct net_device *ndev; |
328 | struct spl2sw_mac *mac; |
329 | u8 mac_addr[ETH_ALEN]; |
330 | int irq, i, ret; |
331 | |
332 | if (platform_get_drvdata(pdev)) |
333 | return -ENODEV; |
334 | |
335 | /* Allocate memory for 'spl2sw_common' area. */ |
336 | comm = devm_kzalloc(dev: &pdev->dev, size: sizeof(*comm), GFP_KERNEL); |
337 | if (!comm) |
338 | return -ENOMEM; |
339 | |
340 | comm->pdev = pdev; |
341 | platform_set_drvdata(pdev, data: comm); |
342 | |
343 | spin_lock_init(&comm->tx_lock); |
344 | spin_lock_init(&comm->mdio_lock); |
345 | spin_lock_init(&comm->int_mask_lock); |
346 | |
347 | /* Get memory resource 0 from dts. */ |
348 | comm->l2sw_reg_base = devm_platform_ioremap_resource(pdev, index: 0); |
349 | if (IS_ERR(ptr: comm->l2sw_reg_base)) |
350 | return PTR_ERR(ptr: comm->l2sw_reg_base); |
351 | |
352 | /* Get irq resource from dts. */ |
353 | ret = platform_get_irq(pdev, 0); |
354 | if (ret < 0) |
355 | return ret; |
356 | irq = ret; |
357 | |
358 | /* Get clock controller. */ |
359 | comm->clk = devm_clk_get(dev: &pdev->dev, NULL); |
360 | if (IS_ERR(ptr: comm->clk)) { |
361 | dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: comm->clk), |
362 | fmt: "Failed to retrieve clock controller!\n" ); |
363 | return PTR_ERR(ptr: comm->clk); |
364 | } |
365 | |
366 | /* Get reset controller. */ |
367 | comm->rstc = devm_reset_control_get_exclusive(dev: &pdev->dev, NULL); |
368 | if (IS_ERR(ptr: comm->rstc)) { |
369 | dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: comm->rstc), |
370 | fmt: "Failed to retrieve reset controller!\n" ); |
371 | return PTR_ERR(ptr: comm->rstc); |
372 | } |
373 | |
374 | /* Enable clock. */ |
375 | ret = clk_prepare_enable(clk: comm->clk); |
376 | if (ret) |
377 | return ret; |
378 | udelay(1); |
379 | |
380 | /* Reset MAC */ |
381 | reset_control_assert(rstc: comm->rstc); |
382 | udelay(1); |
383 | reset_control_deassert(rstc: comm->rstc); |
384 | usleep_range(min: 1000, max: 2000); |
385 | |
386 | /* Request irq. */ |
387 | ret = devm_request_irq(dev: &pdev->dev, irq, handler: spl2sw_ethernet_interrupt, irqflags: 0, |
388 | devname: dev_name(dev: &pdev->dev), dev_id: comm); |
389 | if (ret) { |
390 | dev_err(&pdev->dev, "Failed to request irq #%d!\n" , irq); |
391 | goto out_clk_disable; |
392 | } |
393 | |
394 | /* Initialize TX and RX descriptors. */ |
395 | ret = spl2sw_descs_init(comm); |
396 | if (ret) { |
397 | dev_err(&pdev->dev, "Fail to initialize mac descriptors!\n" ); |
398 | spl2sw_descs_free(comm); |
399 | goto out_clk_disable; |
400 | } |
401 | |
402 | /* Initialize MAC. */ |
403 | spl2sw_mac_init(comm); |
404 | |
405 | /* Initialize mdio bus */ |
406 | ret = spl2sw_mdio_init(comm); |
407 | if (ret) { |
408 | dev_err(&pdev->dev, "Failed to initialize mdio bus!\n" ); |
409 | goto out_clk_disable; |
410 | } |
411 | |
412 | /* Get child node ethernet-ports. */ |
413 | eth_ports_np = of_get_child_by_name(node: pdev->dev.of_node, name: "ethernet-ports" ); |
414 | if (!eth_ports_np) { |
415 | dev_err(&pdev->dev, "No ethernet-ports child node found!\n" ); |
416 | ret = -ENODEV; |
417 | goto out_free_mdio; |
418 | } |
419 | |
420 | for (i = 0; i < MAX_NETDEV_NUM; i++) { |
421 | /* Get port@i of node ethernet-ports. */ |
422 | port_np = spl2sw_get_eth_child_node(ether_np: eth_ports_np, id: i); |
423 | if (!port_np) |
424 | continue; |
425 | |
426 | /* Get phy-mode. */ |
427 | if (of_get_phy_mode(np: port_np, interface: &phy_mode)) { |
428 | dev_err(&pdev->dev, "Failed to get phy-mode property of port@%d!\n" , |
429 | i); |
430 | continue; |
431 | } |
432 | |
433 | /* Get phy-handle. */ |
434 | phy_np = of_parse_phandle(np: port_np, phandle_name: "phy-handle" , index: 0); |
435 | if (!phy_np) { |
436 | dev_err(&pdev->dev, "Failed to get phy-handle property of port@%d!\n" , |
437 | i); |
438 | continue; |
439 | } |
440 | |
441 | /* Get mac-address from nvmem. */ |
442 | ret = spl2sw_nvmem_get_mac_address(dev: &pdev->dev, np: port_np, addrbuf: mac_addr); |
443 | if (ret == -EPROBE_DEFER) { |
444 | goto out_unregister_dev; |
445 | } else if (ret) { |
446 | dev_info(&pdev->dev, "Generate a random mac address!\n" ); |
447 | eth_random_addr(addr: mac_addr); |
448 | } |
449 | |
450 | /* Initialize the net device. */ |
451 | ret = spl2sw_init_netdev(pdev, mac_addr, r_ndev: &ndev); |
452 | if (ret) |
453 | goto out_unregister_dev; |
454 | |
455 | ndev->irq = irq; |
456 | comm->ndev[i] = ndev; |
457 | mac = netdev_priv(dev: ndev); |
458 | mac->phy_node = phy_np; |
459 | mac->phy_mode = phy_mode; |
460 | mac->comm = comm; |
461 | |
462 | mac->lan_port = 0x1 << i; /* forward to port i */ |
463 | mac->to_vlan = 0x1 << i; /* vlan group: i */ |
464 | mac->vlan_id = i; /* vlan group: i */ |
465 | |
466 | /* Set MAC address */ |
467 | ret = spl2sw_mac_addr_add(mac); |
468 | if (ret) |
469 | goto out_unregister_dev; |
470 | |
471 | spl2sw_mac_rx_mode_set(mac); |
472 | } |
473 | |
474 | /* Find first valid net device. */ |
475 | for (i = 0; i < MAX_NETDEV_NUM; i++) { |
476 | if (comm->ndev[i]) |
477 | break; |
478 | } |
479 | if (i >= MAX_NETDEV_NUM) { |
480 | dev_err(&pdev->dev, "No valid ethernet port!\n" ); |
481 | ret = -ENODEV; |
482 | goto out_free_mdio; |
483 | } |
484 | |
485 | /* Save first valid net device */ |
486 | ndev = comm->ndev[i]; |
487 | |
488 | ret = spl2sw_phy_connect(comm); |
489 | if (ret) { |
490 | netdev_err(dev: ndev, format: "Failed to connect phy!\n" ); |
491 | goto out_unregister_dev; |
492 | } |
493 | |
494 | /* Add and enable napi. */ |
495 | netif_napi_add(dev: ndev, napi: &comm->rx_napi, poll: spl2sw_rx_poll); |
496 | napi_enable(n: &comm->rx_napi); |
497 | netif_napi_add_tx(dev: ndev, napi: &comm->tx_napi, poll: spl2sw_tx_poll); |
498 | napi_enable(n: &comm->tx_napi); |
499 | return 0; |
500 | |
501 | out_unregister_dev: |
502 | for (i = 0; i < MAX_NETDEV_NUM; i++) |
503 | if (comm->ndev[i]) |
504 | unregister_netdev(dev: comm->ndev[i]); |
505 | |
506 | out_free_mdio: |
507 | spl2sw_mdio_remove(comm); |
508 | |
509 | out_clk_disable: |
510 | clk_disable_unprepare(clk: comm->clk); |
511 | return ret; |
512 | } |
513 | |
514 | static void spl2sw_remove(struct platform_device *pdev) |
515 | { |
516 | struct spl2sw_common *comm; |
517 | int i; |
518 | |
519 | comm = platform_get_drvdata(pdev); |
520 | |
521 | spl2sw_phy_remove(comm); |
522 | |
523 | /* Unregister and free net device. */ |
524 | for (i = 0; i < MAX_NETDEV_NUM; i++) |
525 | if (comm->ndev[i]) |
526 | unregister_netdev(dev: comm->ndev[i]); |
527 | |
528 | comm->enable = 0; |
529 | spl2sw_mac_hw_stop(comm); |
530 | spl2sw_descs_free(comm); |
531 | |
532 | /* Disable and delete napi. */ |
533 | napi_disable(n: &comm->rx_napi); |
534 | netif_napi_del(napi: &comm->rx_napi); |
535 | napi_disable(n: &comm->tx_napi); |
536 | netif_napi_del(napi: &comm->tx_napi); |
537 | |
538 | spl2sw_mdio_remove(comm); |
539 | |
540 | clk_disable_unprepare(clk: comm->clk); |
541 | } |
542 | |
543 | static const struct of_device_id spl2sw_of_match[] = { |
544 | {.compatible = "sunplus,sp7021-emac" }, |
545 | { /* sentinel */ } |
546 | }; |
547 | |
548 | MODULE_DEVICE_TABLE(of, spl2sw_of_match); |
549 | |
550 | static struct platform_driver spl2sw_driver = { |
551 | .probe = spl2sw_probe, |
552 | .remove_new = spl2sw_remove, |
553 | .driver = { |
554 | .name = "sp7021_emac" , |
555 | .of_match_table = spl2sw_of_match, |
556 | }, |
557 | }; |
558 | |
559 | module_platform_driver(spl2sw_driver); |
560 | |
561 | MODULE_AUTHOR("Wells Lu <wellslutw@gmail.com>" ); |
562 | MODULE_DESCRIPTION("Sunplus Dual 10M/100M Ethernet driver" ); |
563 | MODULE_LICENSE("GPL" ); |
564 | |