Commit 9a1d6af55ecd73938d49076422e87da9f87fc68f
Committed by
Joe Hershberger
1 parent
69a00875e3
Exists in
v2017.01-smarct4x
and in
30 other branches
net: tsec: Add driver model ethernet support
This adds driver model support to Freescale TSEC ethernet driver. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Showing 2 changed files with 196 additions and 0 deletions Side-by-side Diff
drivers/net/tsec.c
... | ... | @@ -10,6 +10,7 @@ |
10 | 10 | |
11 | 11 | #include <config.h> |
12 | 12 | #include <common.h> |
13 | +#include <dm.h> | |
13 | 14 | #include <malloc.h> |
14 | 15 | #include <net.h> |
15 | 16 | #include <command.h> |
... | ... | @@ -21,6 +22,7 @@ |
21 | 22 | |
22 | 23 | DECLARE_GLOBAL_DATA_PTR; |
23 | 24 | |
25 | +#ifndef CONFIG_DM_ETH | |
24 | 26 | /* Default initializations for TSEC controllers. */ |
25 | 27 | |
26 | 28 | static struct tsec_info_struct tsec_info[] = { |
... | ... | @@ -46,6 +48,7 @@ |
46 | 48 | STD_TSEC_INFO(4), /* TSEC4 */ |
47 | 49 | #endif |
48 | 50 | }; |
51 | +#endif /* CONFIG_DM_ETH */ | |
49 | 52 | |
50 | 53 | #define TBIANA_SETTINGS ( \ |
51 | 54 | TBIANA_ASYMMETRIC_PAUSE \ |
52 | 55 | |
... | ... | @@ -98,7 +101,11 @@ |
98 | 101 | * for PowerPC (tm) is usually the case) in the register holds |
99 | 102 | * the entry. |
100 | 103 | */ |
104 | +#ifndef CONFIG_DM_ETH | |
101 | 105 | static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) |
106 | +#else | |
107 | +static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set) | |
108 | +#endif | |
102 | 109 | { |
103 | 110 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
104 | 111 | struct tsec __iomem *regs = priv->regs; |
105 | 112 | |
... | ... | @@ -225,7 +232,11 @@ |
225 | 232 | * do the same. Presumably, this would be zero if there were no |
226 | 233 | * errors |
227 | 234 | */ |
235 | +#ifndef CONFIG_DM_ETH | |
228 | 236 | static int tsec_send(struct eth_device *dev, void *packet, int length) |
237 | +#else | |
238 | +static int tsec_send(struct udevice *dev, void *packet, int length) | |
239 | +#endif | |
229 | 240 | { |
230 | 241 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
231 | 242 | struct tsec __iomem *regs = priv->regs; |
... | ... | @@ -268,6 +279,7 @@ |
268 | 279 | return result; |
269 | 280 | } |
270 | 281 | |
282 | +#ifndef CONFIG_DM_ETH | |
271 | 283 | static int tsec_recv(struct eth_device *dev) |
272 | 284 | { |
273 | 285 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
274 | 286 | |
275 | 287 | |
276 | 288 | |
... | ... | @@ -302,9 +314,61 @@ |
302 | 314 | |
303 | 315 | return -1; |
304 | 316 | } |
317 | +#else | |
318 | +static int tsec_recv(struct udevice *dev, int flags, uchar **packetp) | |
319 | +{ | |
320 | + struct tsec_private *priv = (struct tsec_private *)dev->priv; | |
321 | + struct tsec __iomem *regs = priv->regs; | |
322 | + int ret = -1; | |
305 | 323 | |
324 | + if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) { | |
325 | + int length = in_be16(&priv->rxbd[priv->rx_idx].length); | |
326 | + uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status); | |
327 | + uint32_t buf; | |
328 | + | |
329 | + /* Send the packet up if there were no errors */ | |
330 | + if (!(status & RXBD_STATS)) { | |
331 | + buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr); | |
332 | + *packetp = (uchar *)buf; | |
333 | + ret = length - 4; | |
334 | + } else { | |
335 | + printf("Got error %x\n", (status & RXBD_STATS)); | |
336 | + } | |
337 | + } | |
338 | + | |
339 | + if (in_be32(®s->ievent) & IEVENT_BSY) { | |
340 | + out_be32(®s->ievent, IEVENT_BSY); | |
341 | + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); | |
342 | + } | |
343 | + | |
344 | + return ret; | |
345 | +} | |
346 | + | |
347 | +static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length) | |
348 | +{ | |
349 | + struct tsec_private *priv = (struct tsec_private *)dev->priv; | |
350 | + uint16_t status; | |
351 | + | |
352 | + out_be16(&priv->rxbd[priv->rx_idx].length, 0); | |
353 | + | |
354 | + status = RXBD_EMPTY; | |
355 | + /* Set the wrap bit if this is the last element in the list */ | |
356 | + if ((priv->rx_idx + 1) == PKTBUFSRX) | |
357 | + status |= RXBD_WRAP; | |
358 | + out_be16(&priv->rxbd[priv->rx_idx].status, status); | |
359 | + | |
360 | + priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX; | |
361 | + | |
362 | + return 0; | |
363 | +} | |
364 | +#endif | |
365 | + | |
306 | 366 | /* Stop the interface */ |
367 | +#ifndef CONFIG_DM_ETH | |
307 | 368 | static void tsec_halt(struct eth_device *dev) |
369 | +#else | |
370 | +static void tsec_halt(struct udevice *dev) | |
371 | +#endif | |
308 | 372 | { |
309 | 373 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
310 | 374 | struct tsec __iomem *regs = priv->regs; |
311 | 375 | |
312 | 376 | |
... | ... | @@ -467,9 +531,16 @@ |
467 | 531 | * that it returns success if the link is up, failure otherwise. |
468 | 532 | * This allows U-Boot to find the first active controller. |
469 | 533 | */ |
534 | +#ifndef CONFIG_DM_ETH | |
470 | 535 | static int tsec_init(struct eth_device *dev, bd_t * bd) |
536 | +#else | |
537 | +static int tsec_init(struct udevice *dev) | |
538 | +#endif | |
471 | 539 | { |
472 | 540 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
541 | +#ifdef CONFIG_DM_ETH | |
542 | + struct eth_pdata *pdata = dev_get_platdata(dev); | |
543 | +#endif | |
473 | 544 | struct tsec __iomem *regs = priv->regs; |
474 | 545 | u32 tempval; |
475 | 546 | int ret; |
476 | 547 | |
477 | 548 | |
478 | 549 | |
... | ... | @@ -489,12 +560,21 @@ |
489 | 560 | * order (BE), MACnADDR1 is set to 0xCDAB7856 and |
490 | 561 | * MACnADDR2 is set to 0x34120000. |
491 | 562 | */ |
563 | +#ifndef CONFIG_DM_ETH | |
492 | 564 | tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) | |
493 | 565 | (dev->enetaddr[3] << 8) | dev->enetaddr[2]; |
566 | +#else | |
567 | + tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) | | |
568 | + (pdata->enetaddr[3] << 8) | pdata->enetaddr[2]; | |
569 | +#endif | |
494 | 570 | |
495 | 571 | out_be32(®s->macstnaddr1, tempval); |
496 | 572 | |
573 | +#ifndef CONFIG_DM_ETH | |
497 | 574 | tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16); |
575 | +#else | |
576 | + tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16); | |
577 | +#endif | |
498 | 578 | |
499 | 579 | out_be32(®s->macstnaddr2, tempval); |
500 | 580 | |
... | ... | @@ -600,6 +680,7 @@ |
600 | 680 | return 1; |
601 | 681 | } |
602 | 682 | |
683 | +#ifndef CONFIG_DM_ETH | |
603 | 684 | /* |
604 | 685 | * Initialize device structure. Returns success if PHY |
605 | 686 | * initialization succeeded (i.e. if it recognizes the PHY) |
... | ... | @@ -687,4 +768,109 @@ |
687 | 768 | |
688 | 769 | return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); |
689 | 770 | } |
771 | +#else /* CONFIG_DM_ETH */ | |
772 | +int tsec_probe(struct udevice *dev) | |
773 | +{ | |
774 | + struct tsec_private *priv = dev_get_priv(dev); | |
775 | + struct eth_pdata *pdata = dev_get_platdata(dev); | |
776 | + struct fsl_pq_mdio_info mdio_info; | |
777 | + int offset = 0; | |
778 | + int reg; | |
779 | + const char *phy_mode; | |
780 | + int ret; | |
781 | + | |
782 | + pdata->iobase = (phys_addr_t)dev_get_addr(dev); | |
783 | + priv->regs = (struct tsec *)pdata->iobase; | |
784 | + | |
785 | + offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, | |
786 | + "phy-handle"); | |
787 | + if (offset > 0) { | |
788 | + reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0); | |
789 | + priv->phyaddr = reg; | |
790 | + } else { | |
791 | + debug("phy-handle does not exist under tsec %s\n", dev->name); | |
792 | + return -ENOENT; | |
793 | + } | |
794 | + | |
795 | + offset = fdt_parent_offset(gd->fdt_blob, offset); | |
796 | + if (offset > 0) { | |
797 | + reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0); | |
798 | + priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520); | |
799 | + } else { | |
800 | + debug("No parent node for PHY?\n"); | |
801 | + return -ENOENT; | |
802 | + } | |
803 | + | |
804 | + phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, | |
805 | + "phy-connection-type", NULL); | |
806 | + if (phy_mode) | |
807 | + pdata->phy_interface = phy_get_interface_by_name(phy_mode); | |
808 | + if (pdata->phy_interface == -1) { | |
809 | + debug("Invalid PHY interface '%s'\n", phy_mode); | |
810 | + return -EINVAL; | |
811 | + } | |
812 | + priv->interface = pdata->phy_interface; | |
813 | + | |
814 | + /* Initialize flags */ | |
815 | + priv->flags = TSEC_GIGABIT; | |
816 | + if (priv->interface == PHY_INTERFACE_MODE_SGMII) | |
817 | + priv->flags |= TSEC_SGMII; | |
818 | + | |
819 | + mdio_info.regs = priv->phyregs_sgmii; | |
820 | + mdio_info.name = (char *)dev->name; | |
821 | + ret = fsl_pq_mdio_init(NULL, &mdio_info); | |
822 | + if (ret) | |
823 | + return ret; | |
824 | + | |
825 | + /* Reset the MAC */ | |
826 | + setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); | |
827 | + udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ | |
828 | + clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); | |
829 | + | |
830 | + priv->dev = dev; | |
831 | + priv->bus = miiphy_get_dev_by_name(dev->name); | |
832 | + | |
833 | + /* Try to initialize PHY here, and return */ | |
834 | + return !init_phy(priv); | |
835 | +} | |
836 | + | |
837 | +int tsec_remove(struct udevice *dev) | |
838 | +{ | |
839 | + struct tsec_private *priv = dev->priv; | |
840 | + | |
841 | + free(priv->phydev); | |
842 | + mdio_unregister(priv->bus); | |
843 | + mdio_free(priv->bus); | |
844 | + | |
845 | + return 0; | |
846 | +} | |
847 | + | |
848 | +static const struct eth_ops tsec_ops = { | |
849 | + .start = tsec_init, | |
850 | + .send = tsec_send, | |
851 | + .recv = tsec_recv, | |
852 | + .free_pkt = tsec_free_pkt, | |
853 | + .stop = tsec_halt, | |
854 | +#ifdef CONFIG_MCAST_TFTP | |
855 | + .mcast = tsec_mcast_addr, | |
856 | +#endif | |
857 | +}; | |
858 | + | |
859 | +static const struct udevice_id tsec_ids[] = { | |
860 | + { .compatible = "fsl,tsec" }, | |
861 | + { } | |
862 | +}; | |
863 | + | |
864 | +U_BOOT_DRIVER(eth_tsec) = { | |
865 | + .name = "tsec", | |
866 | + .id = UCLASS_ETH, | |
867 | + .of_match = tsec_ids, | |
868 | + .probe = tsec_probe, | |
869 | + .remove = tsec_remove, | |
870 | + .ops = &tsec_ops, | |
871 | + .priv_auto_alloc_size = sizeof(struct tsec_private), | |
872 | + .platdata_auto_alloc_size = sizeof(struct eth_pdata), | |
873 | + .flags = DM_FLAG_ALLOC_PRIV_DMA, | |
874 | +}; | |
875 | +#endif /* CONFIG_DM_ETH */ |
include/tsec.h
... | ... | @@ -18,6 +18,8 @@ |
18 | 18 | #include <config.h> |
19 | 19 | #include <phy.h> |
20 | 20 | |
21 | +#ifndef CONFIG_DM_ETH | |
22 | + | |
21 | 23 | #ifdef CONFIG_LS102XA |
22 | 24 | #define TSEC_SIZE 0x40000 |
23 | 25 | #define TSEC_MDIO_OFFSET 0x40000 |
... | ... | @@ -64,6 +66,8 @@ |
64 | 66 | x.mii_devname = DEFAULT_MII_NAME;\ |
65 | 67 | } |
66 | 68 | |
69 | +#endif /* CONFIG_DM_ETH */ | |
70 | + | |
67 | 71 | #define MAC_ADDR_LEN 6 |
68 | 72 | |
69 | 73 | /* #define TSEC_TIMEOUT 1000000 */ |
70 | 74 | |
... | ... | @@ -402,7 +406,11 @@ |
402 | 406 | u32 flags; |
403 | 407 | uint rx_idx; /* index of the current RX buffer */ |
404 | 408 | uint tx_idx; /* index of the current TX buffer */ |
409 | +#ifndef CONFIG_DM_ETH | |
405 | 410 | struct eth_device *dev; |
411 | +#else | |
412 | + struct udevice *dev; | |
413 | +#endif | |
406 | 414 | }; |
407 | 415 | |
408 | 416 | struct tsec_info_struct { |
409 | 417 | |
... | ... | @@ -415,8 +423,10 @@ |
415 | 423 | u32 flags; |
416 | 424 | }; |
417 | 425 | |
426 | +#ifndef CONFIG_DM_ETH | |
418 | 427 | int tsec_standard_init(bd_t *bis); |
419 | 428 | int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsec_info, int num); |
429 | +#endif | |
420 | 430 | |
421 | 431 | #endif /* __TSEC_H */ |