Lines Matching +full:sun50i +full:- +full:a64 +full:- +full:dma

5  * SPDX-License-Identifier:     GPL-2.0+
7 * Ethernet driver for H3/A64/A83T based SoC's
10 * LABBE Corentin & Chen-Yu Tsai for Linux, THANKS!
25 #include <asm-generic/gpio.h>
38 #define CONFIG_ETH_BUFSIZE 2048 /* Note must be dma aligned */
74 /* H3/A64 EMAC Register's offset */
148 struct udevice *dev = bus->priv; in sun8i_mdio_read()
166 writel(miiaddr, priv->mac_reg + EMAC_MII_CMD); in sun8i_mdio_read()
170 if (!(readl(priv->mac_reg + EMAC_MII_CMD) & MDIO_CMD_MII_BUSY)) in sun8i_mdio_read()
171 return readl(priv->mac_reg + EMAC_MII_DATA); in sun8i_mdio_read()
175 return -1; in sun8i_mdio_read()
181 struct udevice *dev = bus->priv; in sun8i_mdio_write()
185 int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; in sun8i_mdio_write()
198 writel(val, priv->mac_reg + EMAC_MII_DATA); in sun8i_mdio_write()
199 writel(miiaddr, priv->mac_reg + EMAC_MII_CMD); in sun8i_mdio_write()
203 if (!(readl(priv->mac_reg + EMAC_MII_CMD) & in sun8i_mdio_write()
222 writel(macid_hi, priv->mac_reg + EMAC_ADDR0_HIGH); in _sun8i_write_hwaddr()
223 writel(macid_lo, priv->mac_reg + EMAC_ADDR0_LOW); in _sun8i_write_hwaddr()
233 v = readl(priv->mac_reg + EMAC_CTL0); in sun8i_adjust_link()
235 if (phydev->duplex) in sun8i_adjust_link()
242 switch (phydev->speed) { in sun8i_adjust_link()
253 writel(v, priv->mac_reg + EMAC_CTL0); in sun8i_adjust_link()
258 if (priv->use_internal_phy) { in sun8i_emac_set_syscon_ephy()
264 *reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT; in sun8i_emac_set_syscon_ephy()
281 reg = readl(priv->sysctl_reg); in sun8i_emac_set_syscon()
283 if (priv->variant == H3_EMAC) { in sun8i_emac_set_syscon()
290 if (priv->variant == H3_EMAC || priv->variant == A64_EMAC) in sun8i_emac_set_syscon()
293 switch (priv->interface) { in sun8i_emac_set_syscon()
301 if (priv->variant == H3_EMAC || in sun8i_emac_set_syscon()
302 priv->variant == A64_EMAC) { in sun8i_emac_set_syscon()
309 return -EINVAL; in sun8i_emac_set_syscon()
312 writel(reg, priv->sysctl_reg); in sun8i_emac_set_syscon()
321 phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); in sun8i_phy_init()
323 return -ENODEV; in sun8i_phy_init()
327 priv->phydev = phydev; in sun8i_phy_init()
328 phy_config(priv->phydev); in sun8i_phy_init()
335 struct emac_dma_desc *desc_table_p = &priv->rx_chain[0]; in rx_descs_init()
336 char *rxbuffs = &priv->rxbuffer[0]; in rx_descs_init()
346 desc_p->buf_addr = (uintptr_t)&rxbuffs[idx * CONFIG_ETH_BUFSIZE] in rx_descs_init()
348 desc_p->next = (uintptr_t)&desc_table_p[idx + 1]; in rx_descs_init()
349 desc_p->st |= CONFIG_ETH_RXSIZE; in rx_descs_init()
350 desc_p->status = BIT(31); in rx_descs_init()
354 desc_p->next = (uintptr_t)&desc_table_p[0]; in rx_descs_init()
356 flush_dcache_range((uintptr_t)priv->rx_chain, in rx_descs_init()
357 (uintptr_t)priv->rx_chain + in rx_descs_init()
358 sizeof(priv->rx_chain)); in rx_descs_init()
360 writel((uintptr_t)&desc_table_p[0], (priv->mac_reg + EMAC_RX_DMA_DESC)); in rx_descs_init()
361 priv->rx_currdescnum = 0; in rx_descs_init()
366 struct emac_dma_desc *desc_table_p = &priv->tx_chain[0]; in tx_descs_init()
367 char *txbuffs = &priv->txbuffer[0]; in tx_descs_init()
373 desc_p->buf_addr = (uintptr_t)&txbuffs[idx * CONFIG_ETH_BUFSIZE] in tx_descs_init()
375 desc_p->next = (uintptr_t)&desc_table_p[idx + 1]; in tx_descs_init()
376 desc_p->status = (1 << 31); in tx_descs_init()
377 desc_p->st = 0; in tx_descs_init()
381 desc_p->next = (uintptr_t)&desc_table_p[0]; in tx_descs_init()
384 flush_dcache_range((uintptr_t)priv->tx_chain, in tx_descs_init()
385 (uintptr_t)priv->tx_chain + in tx_descs_init()
386 sizeof(priv->tx_chain)); in tx_descs_init()
388 writel((uintptr_t)&desc_table_p[0], priv->mac_reg + EMAC_TX_DMA_DESC); in tx_descs_init()
389 priv->tx_currdescnum = 0; in tx_descs_init()
397 reg = readl((priv->mac_reg + EMAC_CTL1)); in _sun8i_emac_eth_init()
401 setbits_le32((priv->mac_reg + EMAC_CTL1), 0x1); in _sun8i_emac_eth_init()
403 reg = readl(priv->mac_reg + EMAC_CTL1); in _sun8i_emac_eth_init()
404 } while ((reg & 0x01) != 0 && (--timeout)); in _sun8i_emac_eth_init()
407 return -1; in _sun8i_emac_eth_init()
414 v = readl(priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
415 /* TX_MD Transmission starts after a full frame located in TX DMA FIFO*/ in _sun8i_emac_eth_init()
417 writel(v, priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
419 v = readl(priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
420 /* RX_MD RX DMA reads data from RX DMA FIFO to host memory after a in _sun8i_emac_eth_init()
421 * complete frame has been written to RX DMA FIFO in _sun8i_emac_eth_init()
424 writel(v, priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
426 /* DMA */ in _sun8i_emac_eth_init()
427 writel(8 << 24, priv->mac_reg + EMAC_CTL1); in _sun8i_emac_eth_init()
434 genphy_parse_link(priv->phydev); in _sun8i_emac_eth_init()
436 sun8i_adjust_link(priv, priv->phydev); in _sun8i_emac_eth_init()
438 /* Start RX DMA */ in _sun8i_emac_eth_init()
439 v = readl(priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
441 writel(v, priv->mac_reg + EMAC_RX_CTL1); in _sun8i_emac_eth_init()
442 /* Start TX DMA */ in _sun8i_emac_eth_init()
443 v = readl(priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
445 writel(v, priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_init()
448 setbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31)); in _sun8i_emac_eth_init()
449 setbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31)); in _sun8i_emac_eth_init()
460 offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), in parse_phy_pins()
461 "pinctrl-0"); in parse_phy_pins()
463 printf("WARNING: emac: cannot find pinctrl-0 node\n"); in parse_phy_pins()
467 drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, in parse_phy_pins()
469 pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0, in parse_phy_pins()
474 pin_name = fdt_stringlist_get(gd->fdt_blob, offset, in parse_phy_pins()
480 pin = (pin_name[1] - 'A') << 5; in parse_phy_pins()
492 return -2; in parse_phy_pins()
500 u32 status, desc_num = priv->rx_currdescnum; in _sun8i_eth_recv()
501 struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num]; in _sun8i_eth_recv()
502 int length = -EAGAIN; in _sun8i_eth_recv()
508 ulong data_start = (uintptr_t)desc_p->buf_addr; in _sun8i_eth_recv()
514 status = desc_p->status; in _sun8i_eth_recv()
516 /* Check for DMA own bit */ in _sun8i_eth_recv()
518 length = (desc_p->status >> 16) & 0x3FFF; in _sun8i_eth_recv()
535 return -EMSGSIZE; in _sun8i_eth_recv()
537 *packetp = (uchar *)(ulong)desc_p->buf_addr; in _sun8i_eth_recv()
548 u32 v, desc_num = priv->tx_currdescnum; in _sun8i_emac_eth_send()
549 struct emac_dma_desc *desc_p = &priv->tx_chain[desc_num]; in _sun8i_emac_eth_send()
554 uintptr_t data_start = (uintptr_t)desc_p->buf_addr; in _sun8i_emac_eth_send()
561 desc_p->st = len; in _sun8i_emac_eth_send()
563 desc_p->st |= BIT(24); in _sun8i_emac_eth_send()
571 desc_p->st |= BIT(30); in _sun8i_emac_eth_send()
572 desc_p->st |= BIT(31); in _sun8i_emac_eth_send()
575 desc_p->st |= BIT(29); in _sun8i_emac_eth_send()
576 desc_p->status = BIT(31); in _sun8i_emac_eth_send()
584 priv->tx_currdescnum = desc_num; in _sun8i_emac_eth_send()
586 /* Start the DMA */ in _sun8i_emac_eth_send()
587 v = readl(priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_send()
590 writel(v, priv->mac_reg + EMAC_TX_CTL1); in _sun8i_emac_eth_send()
600 return _sun8i_write_hwaddr(priv, pdata->enetaddr); in sun8i_eth_write_hwaddr()
607 if (priv->use_internal_phy) { in sun8i_emac_board_setup()
609 setbits_le32(&ccm->bus_gate4, BIT(AHB_GATE_OFFSET_EPHY)); in sun8i_emac_board_setup()
612 setbits_le32(&ccm->ahb_reset2_cfg, BIT(AHB_RESET_OFFSET_EPHY)); in sun8i_emac_board_setup()
616 setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC)); in sun8i_emac_board_setup()
618 /* De-assert EMAC */ in sun8i_emac_board_setup()
619 setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC)); in sun8i_emac_board_setup()
625 struct udevice *dev = bus->priv; in sun8i_mdio_reset()
630 if (!dm_gpio_is_valid(&priv->reset_gpio)) in sun8i_mdio_reset()
634 ret = dm_gpio_set_value(&priv->reset_gpio, 0); in sun8i_mdio_reset()
638 udelay(pdata->reset_delays[0]); in sun8i_mdio_reset()
640 ret = dm_gpio_set_value(&priv->reset_gpio, 1); in sun8i_mdio_reset()
644 udelay(pdata->reset_delays[1]); in sun8i_mdio_reset()
646 ret = dm_gpio_set_value(&priv->reset_gpio, 0); in sun8i_mdio_reset()
650 udelay(pdata->reset_delays[2]); in sun8i_mdio_reset()
662 return -ENOMEM; in sun8i_mdio_init()
665 bus->read = sun8i_mdio_read; in sun8i_mdio_init()
666 bus->write = sun8i_mdio_write; in sun8i_mdio_init()
667 snprintf(bus->name, sizeof(bus->name), name); in sun8i_mdio_init()
668 bus->priv = (void *)priv; in sun8i_mdio_init()
670 bus->reset = sun8i_mdio_reset; in sun8i_mdio_init()
680 return _sun8i_emac_eth_init(dev->priv, pdata->enetaddr); in sun8i_emac_eth_start()
699 u32 desc_num = priv->rx_currdescnum; in _sun8i_free_pkt()
700 struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num]; in _sun8i_free_pkt()
706 desc_p->status |= BIT(31); in _sun8i_free_pkt()
711 /* Move to next desc and wrap-around condition. */ in _sun8i_free_pkt()
714 priv->rx_currdescnum = desc_num; in _sun8i_free_pkt()
732 clrbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31)); in sun8i_emac_eth_stop()
733 clrbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31)); in sun8i_emac_eth_stop()
735 /* Stop TX DMA */ in sun8i_emac_eth_stop()
736 clrbits_le32(priv->mac_reg + EMAC_TX_CTL1, BIT(30)); in sun8i_emac_eth_stop()
738 phy_shutdown(priv->phydev); in sun8i_emac_eth_stop()
746 priv->mac_reg = (void *)pdata->iobase; in sun8i_emac_eth_probe()
751 sun8i_mdio_init(dev->name, dev); in sun8i_emac_eth_probe()
752 priv->bus = miiphy_get_dev_by_name(dev->name); in sun8i_emac_eth_probe()
769 struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; in sun8i_emac_eth_ofdata_to_platdata()
779 pdata->iobase = devfdt_get_addr_name(dev, "emac"); in sun8i_emac_eth_ofdata_to_platdata()
780 priv->sysctl_reg = devfdt_get_addr_name(dev, "syscon"); in sun8i_emac_eth_ofdata_to_platdata()
782 pdata->phy_interface = -1; in sun8i_emac_eth_ofdata_to_platdata()
783 priv->phyaddr = -1; in sun8i_emac_eth_ofdata_to_platdata()
784 priv->use_internal_phy = false; in sun8i_emac_eth_ofdata_to_platdata()
786 offset = fdtdec_lookup_phandle(gd->fdt_blob, node, in sun8i_emac_eth_ofdata_to_platdata()
789 priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", in sun8i_emac_eth_ofdata_to_platdata()
790 -1); in sun8i_emac_eth_ofdata_to_platdata()
792 phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL); in sun8i_emac_eth_ofdata_to_platdata()
795 pdata->phy_interface = phy_get_interface_by_name(phy_mode); in sun8i_emac_eth_ofdata_to_platdata()
796 printf("phy interface%d\n", pdata->phy_interface); in sun8i_emac_eth_ofdata_to_platdata()
798 if (pdata->phy_interface == -1) { in sun8i_emac_eth_ofdata_to_platdata()
800 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
803 priv->variant = dev_get_driver_data(dev); in sun8i_emac_eth_ofdata_to_platdata()
805 if (!priv->variant) { in sun8i_emac_eth_ofdata_to_platdata()
807 (char *)priv->variant); in sun8i_emac_eth_ofdata_to_platdata()
808 return -EINVAL; in sun8i_emac_eth_ofdata_to_platdata()
811 if (priv->variant == H3_EMAC) { in sun8i_emac_eth_ofdata_to_platdata()
812 if (fdt_getprop(gd->fdt_blob, node, in sun8i_emac_eth_ofdata_to_platdata()
813 "allwinner,use-internal-phy", NULL)) in sun8i_emac_eth_ofdata_to_platdata()
814 priv->use_internal_phy = true; in sun8i_emac_eth_ofdata_to_platdata()
817 priv->interface = pdata->phy_interface; in sun8i_emac_eth_ofdata_to_platdata()
819 if (!priv->use_internal_phy) in sun8i_emac_eth_ofdata_to_platdata()
823 if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), in sun8i_emac_eth_ofdata_to_platdata()
824 "snps,reset-active-low")) in sun8i_emac_eth_ofdata_to_platdata()
827 ret = gpio_request_by_name(dev, "snps,reset-gpio", 0, in sun8i_emac_eth_ofdata_to_platdata()
828 &priv->reset_gpio, reset_flags); in sun8i_emac_eth_ofdata_to_platdata()
831 ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), in sun8i_emac_eth_ofdata_to_platdata()
832 "snps,reset-delays-us", in sun8i_emac_eth_ofdata_to_platdata()
833 sun8i_pdata->reset_delays, 3); in sun8i_emac_eth_ofdata_to_platdata()
834 } else if (ret == -ENOENT) { in sun8i_emac_eth_ofdata_to_platdata()
843 {.compatible = "allwinner,sun8i-h3-emac", .data = (uintptr_t)H3_EMAC },
844 {.compatible = "allwinner,sun50i-a64-emac",
846 {.compatible = "allwinner,sun8i-a83t-emac",