Lines Matching +full:sun8i +full:- +full:a83t +full:- +full:emac

1 // SPDX-License-Identifier: GPL-2.0+
6 * Ethernet driver for H3/A64/A83T based SoC's
9 * LABBE Corentin & Chen-Yu Tsai for Linux, THANKS!
23 #include <dt-bindings/pinctrl/sun4i-a10.h>
25 #include <asm-generic/gpio.h>
77 /* H3/A64 EMAC Register's offset */
154 struct udevice *dev = bus->priv; in sun8i_mdio_read()
172 writel(miiaddr, priv->mac_reg + EMAC_MII_CMD); in sun8i_mdio_read()
176 if (!(readl(priv->mac_reg + EMAC_MII_CMD) & MDIO_CMD_MII_BUSY)) in sun8i_mdio_read()
177 return readl(priv->mac_reg + EMAC_MII_DATA); in sun8i_mdio_read()
181 return -1; in sun8i_mdio_read()
187 struct udevice *dev = bus->priv; in sun8i_mdio_write()
191 int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; in sun8i_mdio_write()
204 writel(val, priv->mac_reg + EMAC_MII_DATA); in sun8i_mdio_write()
205 writel(miiaddr, priv->mac_reg + EMAC_MII_CMD); in sun8i_mdio_write()
209 if (!(readl(priv->mac_reg + EMAC_MII_CMD) & in sun8i_mdio_write()
228 writel(macid_hi, priv->mac_reg + EMAC_ADDR0_HIGH); in _sun8i_write_hwaddr()
229 writel(macid_lo, priv->mac_reg + EMAC_ADDR0_LOW); in _sun8i_write_hwaddr()
239 v = readl(priv->mac_reg + EMAC_CTL0); in sun8i_adjust_link()
241 if (phydev->duplex) in sun8i_adjust_link()
248 switch (phydev->speed) { in sun8i_adjust_link()
259 writel(v, priv->mac_reg + EMAC_CTL0); in sun8i_adjust_link()
264 if (priv->use_internal_phy) { in sun8i_emac_set_syscon_ephy()
270 *reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT; in sun8i_emac_set_syscon_ephy()
288 reg = readl(priv->sysctl_reg + 0x30); in sun8i_emac_set_syscon()
290 if (priv->variant == R40_GMAC) in sun8i_emac_set_syscon()
293 if (priv->variant == H3_EMAC) { in sun8i_emac_set_syscon()
300 if (priv->variant == H3_EMAC || priv->variant == A64_EMAC) in sun8i_emac_set_syscon()
303 switch (priv->interface) { in sun8i_emac_set_syscon()
311 if (priv->variant == H3_EMAC || in sun8i_emac_set_syscon()
312 priv->variant == A64_EMAC) { in sun8i_emac_set_syscon()
316 /* RMII not supported on A83T */ in sun8i_emac_set_syscon()
319 return -EINVAL; in sun8i_emac_set_syscon()
322 if (pdata->tx_delay_ps) in sun8i_emac_set_syscon()
323 reg |= ((pdata->tx_delay_ps / 100) << SC_ETXDC_OFFSET) in sun8i_emac_set_syscon()
326 if (pdata->rx_delay_ps) in sun8i_emac_set_syscon()
327 reg |= ((pdata->rx_delay_ps / 100) << SC_ERXDC_OFFSET) in sun8i_emac_set_syscon()
330 writel(reg, priv->sysctl_reg + 0x30); in sun8i_emac_set_syscon()
339 phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); in sun8i_phy_init()
341 return -ENODEV; in sun8i_phy_init()
345 priv->phydev = phydev; in sun8i_phy_init()
346 phy_config(priv->phydev); in sun8i_phy_init()
353 struct emac_dma_desc *desc_table_p = &priv->rx_chain[0]; in rx_descs_init()
354 char *rxbuffs = &priv->rxbuffer[0]; in rx_descs_init()
364 desc_p->buf_addr = (uintptr_t)&rxbuffs[idx * CONFIG_ETH_BUFSIZE] in rx_descs_init()
366 desc_p->next = (uintptr_t)&desc_table_p[idx + 1]; in rx_descs_init()
367 desc_p->st |= CONFIG_ETH_RXSIZE; in rx_descs_init()
368 desc_p->status = BIT(31); in rx_descs_init()
372 desc_p->next = (uintptr_t)&desc_table_p[0]; in rx_descs_init()
374 flush_dcache_range((uintptr_t)priv->rx_chain, in rx_descs_init()
375 (uintptr_t)priv->rx_chain + in rx_descs_init()
376 sizeof(priv->rx_chain)); in rx_descs_init()
378 writel((uintptr_t)&desc_table_p[0], (priv->mac_reg + EMAC_RX_DMA_DESC)); in rx_descs_init()
379 priv->rx_currdescnum = 0; in rx_descs_init()
384 struct emac_dma_desc *desc_table_p = &priv->tx_chain[0]; in tx_descs_init()
385 char *txbuffs = &priv->txbuffer[0]; in tx_descs_init()
391 desc_p->buf_addr = (uintptr_t)&txbuffs[idx * CONFIG_ETH_BUFSIZE] in tx_descs_init()
393 desc_p->next = (uintptr_t)&desc_table_p[idx + 1]; in tx_descs_init()
394 desc_p->status = (1 << 31); in tx_descs_init()
395 desc_p->st = 0; in tx_descs_init()
399 desc_p->next = (uintptr_t)&desc_table_p[0]; in tx_descs_init()
402 flush_dcache_range((uintptr_t)priv->tx_chain, in tx_descs_init()
403 (uintptr_t)priv->tx_chain + in tx_descs_init()
404 sizeof(priv->tx_chain)); in tx_descs_init()
406 writel((uintptr_t)&desc_table_p[0], priv->mac_reg + EMAC_TX_DMA_DESC); in tx_descs_init()
407 priv->tx_currdescnum = 0; in tx_descs_init()
415 reg = readl((priv->mac_reg + EMAC_CTL1)); in _sun8i_emac_eth_init()
419 setbits_le32((priv->mac_reg + EMAC_CTL1), 0x1); in _sun8i_emac_eth_init()
421 reg = readl(priv->mac_reg + EMAC_CTL1); in _sun8i_emac_eth_init()
422 } while ((reg & 0x01) != 0 && (--timeout)); in _sun8i_emac_eth_init()
425 return -1; in _sun8i_emac_eth_init()
432 v = readl(priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
435 writel(v, priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
437 v = readl(priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
442 writel(v, priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
445 writel(8 << 24, priv->mac_reg + EMAC_CTL1); in _sun8i_emac_eth_init()
452 phy_startup(priv->phydev); in _sun8i_emac_eth_init()
454 sun8i_adjust_link(priv, priv->phydev); in _sun8i_emac_eth_init()
457 v = readl(priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
459 writel(v, priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
461 v = readl(priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
463 writel(v, priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
466 setbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31)); in _sun8i_emac_eth_init()
467 setbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31)); in _sun8i_emac_eth_init()
479 offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), in parse_phy_pins()
480 "pinctrl-0"); in parse_phy_pins()
482 printf("WARNING: emac: cannot find pinctrl-0 node\n"); in parse_phy_pins()
486 drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, in parse_phy_pins()
487 "drive-strength", ~0); in parse_phy_pins()
499 if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-up", NULL)) in parse_phy_pins()
501 else if (fdt_get_property(gd->fdt_blob, offset, "bias-pull-down", NULL)) in parse_phy_pins()
507 pin_name = fdt_stringlist_get(gd->fdt_blob, offset, in parse_phy_pins()
516 if (priv->variant == H3_EMAC) in parse_phy_pins()
518 else if (priv->variant == R40_GMAC) in parse_phy_pins()
530 printf("WARNING: emac: cannot find pins property\n"); in parse_phy_pins()
531 return -2; in parse_phy_pins()
539 u32 status, desc_num = priv->rx_currdescnum; in _sun8i_eth_recv()
540 struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num]; in _sun8i_eth_recv()
541 int length = -EAGAIN; in _sun8i_eth_recv()
547 ulong data_start = (uintptr_t)desc_p->buf_addr; in _sun8i_eth_recv()
553 status = desc_p->status; in _sun8i_eth_recv()
557 length = (desc_p->status >> 16) & 0x3FFF; in _sun8i_eth_recv()
574 return -EMSGSIZE; in _sun8i_eth_recv()
576 *packetp = (uchar *)(ulong)desc_p->buf_addr; in _sun8i_eth_recv()
587 u32 v, desc_num = priv->tx_currdescnum; in _sun8i_emac_eth_send()
588 struct emac_dma_desc *desc_p = &priv->tx_chain[desc_num]; in _sun8i_emac_eth_send()
593 uintptr_t data_start = (uintptr_t)desc_p->buf_addr; in _sun8i_emac_eth_send()
600 desc_p->st = len; in _sun8i_emac_eth_send()
602 desc_p->st |= BIT(24); in _sun8i_emac_eth_send()
610 desc_p->st |= BIT(30); in _sun8i_emac_eth_send()
611 desc_p->st |= BIT(31); in _sun8i_emac_eth_send()
614 desc_p->st |= BIT(29); in _sun8i_emac_eth_send()
615 desc_p->status = BIT(31); in _sun8i_emac_eth_send()
623 priv->tx_currdescnum = desc_num; in _sun8i_emac_eth_send()
626 v = readl(priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_send()
629 writel(v, priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_send()
639 return _sun8i_write_hwaddr(priv, pdata->enetaddr); in sun8i_eth_write_hwaddr()
646 if (priv->variant == H3_EMAC) { in sun8i_emac_board_setup()
648 if (priv->use_internal_phy) { in sun8i_emac_board_setup()
650 setbits_le32(&ccm->bus_gate4, in sun8i_emac_board_setup()
654 setbits_le32(&ccm->ahb_reset2_cfg, in sun8i_emac_board_setup()
659 if (priv->variant == R40_GMAC) { in sun8i_emac_board_setup()
660 /* Set clock gating for emac */ in sun8i_emac_board_setup()
661 setbits_le32(&ccm->ahb_reset1_cfg, BIT(AHB_RESET_OFFSET_GMAC)); in sun8i_emac_board_setup()
663 /* De-assert EMAC */ in sun8i_emac_board_setup()
664 setbits_le32(&ccm->ahb_gate1, BIT(AHB_GATE_OFFSET_GMAC)); in sun8i_emac_board_setup()
667 setbits_le32(&ccm->gmac_clk_cfg, in sun8i_emac_board_setup()
670 setbits_le32(&ccm->gmac_clk_cfg, in sun8i_emac_board_setup()
673 /* Set clock gating for emac */ in sun8i_emac_board_setup()
674 setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC)); in sun8i_emac_board_setup()
676 /* De-assert EMAC */ in sun8i_emac_board_setup()
677 setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC)); in sun8i_emac_board_setup()
684 struct udevice *dev = bus->priv; in sun8i_mdio_reset()
689 if (!dm_gpio_is_valid(&priv->reset_gpio)) in sun8i_mdio_reset()
693 ret = dm_gpio_set_value(&priv->reset_gpio, 0); in sun8i_mdio_reset()
697 udelay(pdata->reset_delays[0]); in sun8i_mdio_reset()
699 ret = dm_gpio_set_value(&priv->reset_gpio, 1); in sun8i_mdio_reset()
703 udelay(pdata->reset_delays[1]); in sun8i_mdio_reset()
705 ret = dm_gpio_set_value(&priv->reset_gpio, 0); in sun8i_mdio_reset()
709 udelay(pdata->reset_delays[2]); in sun8i_mdio_reset()
721 return -ENOMEM; in sun8i_mdio_init()
724 bus->read = sun8i_mdio_read; in sun8i_mdio_init()
725 bus->write = sun8i_mdio_write; in sun8i_mdio_init()
726 snprintf(bus->name, sizeof(bus->name), name); in sun8i_mdio_init()
727 bus->priv = (void *)priv; in sun8i_mdio_init()
729 bus->reset = sun8i_mdio_reset; in sun8i_mdio_init()
739 return _sun8i_emac_eth_init(dev->priv, pdata->enetaddr); in sun8i_emac_eth_start()
758 u32 desc_num = priv->rx_currdescnum; in _sun8i_free_pkt()
759 struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num]; in _sun8i_free_pkt()
765 desc_p->status |= BIT(31); in _sun8i_free_pkt()
770 /* Move to next desc and wrap-around condition. */ in _sun8i_free_pkt()
773 priv->rx_currdescnum = desc_num; in _sun8i_free_pkt()
791 clrbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31)); in sun8i_emac_eth_stop()
792 clrbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31)); in sun8i_emac_eth_stop()
795 clrbits_le32(priv->mac_reg + EMAC_TX_CTL1, BIT(30)); in sun8i_emac_eth_stop()
797 phy_shutdown(priv->phydev); in sun8i_emac_eth_stop()
803 struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; in sun8i_emac_eth_probe()
806 priv->mac_reg = (void *)pdata->iobase; in sun8i_emac_eth_probe()
811 sun8i_mdio_init(dev->name, dev); in sun8i_emac_eth_probe()
812 priv->bus = miiphy_get_dev_by_name(dev->name); in sun8i_emac_eth_probe()
829 struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; in sun8i_emac_eth_ofdata_to_platdata()
840 pdata->iobase = devfdt_get_addr(dev); in sun8i_emac_eth_ofdata_to_platdata()
841 if (pdata->iobase == FDT_ADDR_T_NONE) { in sun8i_emac_eth_ofdata_to_platdata()
843 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
846 priv->variant = dev_get_driver_data(dev); in sun8i_emac_eth_ofdata_to_platdata()
848 if (!priv->variant) { in sun8i_emac_eth_ofdata_to_platdata()
850 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
853 if (priv->variant != R40_GMAC) { in sun8i_emac_eth_ofdata_to_platdata()
854 offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "syscon"); in sun8i_emac_eth_ofdata_to_platdata()
857 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
859 reg = fdt_getprop(gd->fdt_blob, offset, "reg", NULL); in sun8i_emac_eth_ofdata_to_platdata()
863 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
865 priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob, in sun8i_emac_eth_ofdata_to_platdata()
867 if (priv->sysctl_reg == FDT_ADDR_T_NONE) { in sun8i_emac_eth_ofdata_to_platdata()
870 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
874 pdata->phy_interface = -1; in sun8i_emac_eth_ofdata_to_platdata()
875 priv->phyaddr = -1; in sun8i_emac_eth_ofdata_to_platdata()
876 priv->use_internal_phy = false; in sun8i_emac_eth_ofdata_to_platdata()
878 offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy-handle"); in sun8i_emac_eth_ofdata_to_platdata()
881 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
883 priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1); in sun8i_emac_eth_ofdata_to_platdata()
885 phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL); in sun8i_emac_eth_ofdata_to_platdata()
888 pdata->phy_interface = phy_get_interface_by_name(phy_mode); in sun8i_emac_eth_ofdata_to_platdata()
889 printf("phy interface%d\n", pdata->phy_interface); in sun8i_emac_eth_ofdata_to_platdata()
891 if (pdata->phy_interface == -1) { in sun8i_emac_eth_ofdata_to_platdata()
893 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
896 if (priv->variant == H3_EMAC) { in sun8i_emac_eth_ofdata_to_platdata()
897 int parent = fdt_parent_offset(gd->fdt_blob, offset); in sun8i_emac_eth_ofdata_to_platdata()
900 !fdt_node_check_compatible(gd->fdt_blob, parent, in sun8i_emac_eth_ofdata_to_platdata()
901 "allwinner,sun8i-h3-mdio-internal")) in sun8i_emac_eth_ofdata_to_platdata()
902 priv->use_internal_phy = true; in sun8i_emac_eth_ofdata_to_platdata()
905 priv->interface = pdata->phy_interface; in sun8i_emac_eth_ofdata_to_platdata()
907 if (!priv->use_internal_phy) in sun8i_emac_eth_ofdata_to_platdata()
910 sun8i_pdata->tx_delay_ps = fdtdec_get_int(gd->fdt_blob, node, in sun8i_emac_eth_ofdata_to_platdata()
911 "allwinner,tx-delay-ps", 0); in sun8i_emac_eth_ofdata_to_platdata()
912 if (sun8i_pdata->tx_delay_ps < 0 || sun8i_pdata->tx_delay_ps > 700) in sun8i_emac_eth_ofdata_to_platdata()
914 sun8i_pdata->tx_delay_ps); in sun8i_emac_eth_ofdata_to_platdata()
916 sun8i_pdata->rx_delay_ps = fdtdec_get_int(gd->fdt_blob, node, in sun8i_emac_eth_ofdata_to_platdata()
917 "allwinner,rx-delay-ps", 0); in sun8i_emac_eth_ofdata_to_platdata()
918 if (sun8i_pdata->rx_delay_ps < 0 || sun8i_pdata->rx_delay_ps > 3100) in sun8i_emac_eth_ofdata_to_platdata()
920 sun8i_pdata->rx_delay_ps); in sun8i_emac_eth_ofdata_to_platdata()
923 if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), in sun8i_emac_eth_ofdata_to_platdata()
924 "snps,reset-active-low")) in sun8i_emac_eth_ofdata_to_platdata()
927 ret = gpio_request_by_name(dev, "snps,reset-gpio", 0, in sun8i_emac_eth_ofdata_to_platdata()
928 &priv->reset_gpio, reset_flags); in sun8i_emac_eth_ofdata_to_platdata()
931 ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), in sun8i_emac_eth_ofdata_to_platdata()
932 "snps,reset-delays-us", in sun8i_emac_eth_ofdata_to_platdata()
933 sun8i_pdata->reset_delays, 3); in sun8i_emac_eth_ofdata_to_platdata()
934 } else if (ret == -ENOENT) { in sun8i_emac_eth_ofdata_to_platdata()
943 {.compatible = "allwinner,sun8i-h3-emac", .data = (uintptr_t)H3_EMAC },
944 {.compatible = "allwinner,sun50i-a64-emac",
946 {.compatible = "allwinner,sun8i-a83t-emac",
948 {.compatible = "allwinner,sun8i-r40-gmac",