diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/Kconfig | 7 | ||||
-rw-r--r-- | drivers/net/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/fm/eth.c | 433 | ||||
-rw-r--r-- | drivers/net/fm/fm.c | 80 | ||||
-rw-r--r-- | drivers/net/fm/fm.h | 23 | ||||
-rw-r--r-- | drivers/net/fm/init.c | 2 | ||||
-rw-r--r-- | drivers/net/fm/memac.c | 1 | ||||
-rw-r--r-- | drivers/net/fm/memac_phy.c | 139 | ||||
-rw-r--r-- | drivers/net/fsl-mc/mc.c | 48 | ||||
-rw-r--r-- | drivers/net/fsl_ls_mdio.c | 146 | ||||
-rw-r--r-- | drivers/net/ldpaa_eth/ldpaa_eth.c | 232 | ||||
-rw-r--r-- | drivers/net/ldpaa_eth/ldpaa_eth.h | 6 |
12 files changed, 1025 insertions, 93 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4d1013c984..bc518f218d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -640,4 +640,11 @@ config MVMDIO This driver is used by the MVPP2 and MVNETA drivers. +config FSL_LS_MDIO + bool "NXP Layerscape MDIO interface support" + depends on DM_MDIO + help + This driver supports the MDIO bus found on the Fman 10G Ethernet MACs and + on the mEMAC (which supports both Clauses 22 and 45). + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6e0a68834d..6d9b8772b1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o +obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c index 88019c9a88..5f1a023352 100644 --- a/drivers/net/fm/eth.c +++ b/drivers/net/fm/eth.c @@ -1,10 +1,17 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2009-2012 Freescale Semiconductor, Inc. + * Copyright 2020 NXP * Dave Liu <daveliu@freescale.com> */ #include <common.h> #include <asm/io.h> +#ifdef CONFIG_DM_ETH +#include <dm.h> +#include <dm/ofnode.h> +#include <linux/compat.h> +#include <phy_interface.h> +#endif #include <malloc.h> #include <net.h> #include <hwconfig.h> @@ -18,8 +25,10 @@ #include "fm.h" +#ifndef CONFIG_DM_ETH static struct eth_device *devlist[NUM_FM_PORTS]; static int num_controllers; +#endif #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) @@ -37,10 +46,18 @@ static void dtsec_configure_serdes(struct fm_eth *priv) #ifdef CONFIG_SYS_FMAN_V3 u32 value; struct mii_dev bus; - bus.priv = priv->mac->phyregs; bool sgmii_2500 = (priv->enet_if == PHY_INTERFACE_MODE_SGMII_2500) ? true : false; - int i = 0; + int i = 0, j; + +#ifndef CONFIG_DM_ETH + bus.priv = priv->mac->phyregs; +#else + bus.priv = priv->pcs_mdio; +#endif + bus.read = memac_mdio_read; + bus.write = memac_mdio_write; + bus.reset = memac_mdio_reset; qsgmii_loop: /* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */ @@ -51,6 +68,10 @@ qsgmii_loop: else value = PHY_SGMII_IF_MODE_SGMII | PHY_SGMII_IF_MODE_AN; + for (j = 0; j <= 3; j++) + debug("dump PCS reg %#x: %#x\n", j, + memac_mdio_read(&bus, i, MDIO_DEVAD_NONE, j)); + memac_mdio_write(&bus, i, MDIO_DEVAD_NONE, 0x14, value); /* Dev ability according to SGMII specification */ @@ -98,9 +119,8 @@ qsgmii_loop: #endif } -static void dtsec_init_phy(struct eth_device *dev) +static void dtsec_init_phy(struct fm_eth *fm_eth) { - struct fm_eth *fm_eth = dev->priv; #ifndef CONFIG_SYS_FMAN_V3 struct dtsec *regs = (struct dtsec *)CONFIG_SYS_FSL_FM1_DTSEC1_ADDR; @@ -114,10 +134,10 @@ static void dtsec_init_phy(struct eth_device *dev) dtsec_configure_serdes(fm_eth); } +#ifndef CONFIG_DM_ETH #ifdef CONFIG_PHYLIB -static int tgec_is_fibre(struct eth_device *dev) +static int tgec_is_fibre(struct fm_eth *fm) { - struct fm_eth *fm = dev->priv; char phyopt[20]; sprintf(phyopt, "fsl_fm%d_xaui_phy", fm->fm_index + 1); @@ -125,6 +145,7 @@ static int tgec_is_fibre(struct eth_device *dev) return hwconfig_arg_cmp(phyopt, "xfi"); } #endif +#endif /* CONFIG_DM_ETH */ #endif static u16 muram_readw(u16 *addr) @@ -168,6 +189,8 @@ static void bmi_rx_port_disable(struct fm_bmi_rx_port *rx_port) /* wait until the rx port is not busy */ while ((in_be32(&rx_port->fmbm_rst) & FMBM_RST_BSY) && timeout--) ; + if (!timeout) + printf("%s - timeout\n", __func__); } static void bmi_rx_port_init(struct fm_bmi_rx_port *rx_port) @@ -196,6 +219,8 @@ static void bmi_tx_port_disable(struct fm_bmi_tx_port *tx_port) /* wait until the tx port is not busy */ while ((in_be32(&tx_port->fmbm_tst) & FMBM_TST_BSY) && timeout--) ; + if (!timeout) + printf("%s - timeout\n", __func__); } static void bmi_tx_port_init(struct fm_bmi_tx_port *tx_port) @@ -435,23 +460,39 @@ static void fmc_tx_port_graceful_stop_disable(struct fm_eth *fm_eth) sync(); } +#ifndef CONFIG_DM_ETH static int fm_eth_open(struct eth_device *dev, bd_t *bd) +#else +static int fm_eth_open(struct udevice *dev) +#endif { - struct fm_eth *fm_eth; +#ifndef CONFIG_DM_ETH + struct fm_eth *fm_eth = dev->priv; +#else + struct eth_pdata *pdata = dev_get_platdata(dev); + struct fm_eth *fm_eth = dev_get_priv(dev); +#endif + unsigned char *enetaddr; struct fsl_enet_mac *mac; #ifdef CONFIG_PHYLIB int ret; #endif - fm_eth = (struct fm_eth *)dev->priv; mac = fm_eth->mac; +#ifndef CONFIG_DM_ETH + enetaddr = &dev->enetaddr[0]; +#else + enetaddr = pdata->enetaddr; +#endif + /* setup the MAC address */ - if (dev->enetaddr[0] & 0x01) { - printf("%s: MacAddress is multcast address\n", __func__); - return 1; + if (enetaddr[0] & 0x01) { + printf("%s: MacAddress is multicast address\n", __func__); + enetaddr[0] = 0; + enetaddr[5] = fm_eth->num; } - mac->set_mac_addr(mac, dev->enetaddr); + mac->set_mac_addr(mac, enetaddr); /* enable bmi Rx port */ setbits_be32(&fm_eth->rx_port->fmbm_rcfg, FMBM_RCFG_EN); @@ -466,8 +507,12 @@ static int fm_eth_open(struct eth_device *dev, bd_t *bd) if (fm_eth->phydev) { ret = phy_startup(fm_eth->phydev); if (ret) { +#ifndef CONFIG_DM_ETH printf("%s: Could not initialize\n", fm_eth->phydev->dev->name); +#else + printf("%s: Could not initialize\n", dev->name); +#endif return ret; } } else { @@ -481,6 +526,8 @@ static int fm_eth_open(struct eth_device *dev, bd_t *bd) /* set the MAC-PHY mode */ mac->set_if_mode(mac, fm_eth->enet_if, fm_eth->phydev->speed); + debug("MAC IF mode %d, speed %d, link %d\n", fm_eth->enet_if, + fm_eth->phydev->speed, fm_eth->phydev->link); if (!fm_eth->phydev->link) printf("%s: No link.\n", fm_eth->phydev->dev->name); @@ -488,7 +535,11 @@ static int fm_eth_open(struct eth_device *dev, bd_t *bd) return fm_eth->phydev->link ? 0 : -1; } +#ifndef CONFIG_DM_ETH static void fm_eth_halt(struct eth_device *dev) +#else +static void fm_eth_halt(struct udevice *dev) +#endif { struct fm_eth *fm_eth; struct fsl_enet_mac *mac; @@ -511,7 +562,11 @@ static void fm_eth_halt(struct eth_device *dev) #endif } +#ifndef CONFIG_DM_ETH static int fm_eth_send(struct eth_device *dev, void *buf, int len) +#else +static int fm_eth_send(struct udevice *dev, void *buf, int len) +#endif { struct fm_eth *fm_eth; struct fm_port_global_pram *pram; @@ -569,20 +624,50 @@ static int fm_eth_send(struct eth_device *dev, void *buf, int len) return 1; } -static int fm_eth_recv(struct eth_device *dev) +static struct fm_port_bd *fm_eth_free_one(struct fm_eth *fm_eth, + struct fm_port_bd *rxbd) { - struct fm_eth *fm_eth; struct fm_port_global_pram *pram; - struct fm_port_bd *rxbd, *rxbd_base; - u16 status, len; - u32 buf_lo, buf_hi; - u8 *data; + struct fm_port_bd *rxbd_base; u16 offset_out; - int ret = 1; - fm_eth = (struct fm_eth *)dev->priv; pram = fm_eth->rx_pram; - rxbd = fm_eth->cur_rxbd; + + /* clear the RxBDs */ + muram_writew(&rxbd->status, RxBD_EMPTY); + muram_writew(&rxbd->len, 0); + sync(); + + /* advance RxBD */ + rxbd++; + rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring; + if (rxbd >= (rxbd_base + RX_BD_RING_SIZE)) + rxbd = rxbd_base; + + /* update RxQD */ + offset_out = muram_readw(&pram->rxqd.offset_out); + offset_out += sizeof(struct fm_port_bd); + if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size)) + offset_out = 0; + muram_writew(&pram->rxqd.offset_out, offset_out); + sync(); + + return rxbd; +} + +#ifndef CONFIG_DM_ETH +static int fm_eth_recv(struct eth_device *dev) +#else +static int fm_eth_recv(struct udevice *dev, int flags, uchar **packetp) +#endif +{ + struct fm_eth *fm_eth = (struct fm_eth *)dev->priv; + struct fm_port_bd *rxbd = fm_eth->cur_rxbd; + u32 buf_lo, buf_hi; + u16 status, len; + int ret = -1; + u8 *data; + status = muram_readw(&rxbd->status); while (!(status & RxBD_EMPTY)) { @@ -591,38 +676,40 @@ static int fm_eth_recv(struct eth_device *dev) buf_lo = in_be32(&rxbd->buf_ptr_lo); data = (u8 *)((ulong)(buf_hi << 16) << 16 | buf_lo); len = muram_readw(&rxbd->len); +#ifndef CONFIG_DM_ETH net_process_received_packet(data, len); +#else + *packetp = data; + return len; +#endif } else { printf("%s: Rx error\n", dev->name); ret = 0; } - /* clear the RxBDs */ - muram_writew(&rxbd->status, RxBD_EMPTY); - muram_writew(&rxbd->len, 0); - sync(); + /* free current bd, advance to next one */ + rxbd = fm_eth_free_one(fm_eth, rxbd); - /* advance RxBD */ - rxbd++; - rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring; - if (rxbd >= (rxbd_base + RX_BD_RING_SIZE)) - rxbd = rxbd_base; /* read next status */ status = muram_readw(&rxbd->status); - - /* update RxQD */ - offset_out = muram_readw(&pram->rxqd.offset_out); - offset_out += sizeof(struct fm_port_bd); - if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size)) - offset_out = 0; - muram_writew(&pram->rxqd.offset_out, offset_out); - sync(); } fm_eth->cur_rxbd = (void *)rxbd; return ret; } +#ifdef CONFIG_DM_ETH +static int fm_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct fm_eth *fm_eth = (struct fm_eth *)dev->priv; + + fm_eth->cur_rxbd = fm_eth_free_one(fm_eth, fm_eth->cur_rxbd); + + return 0; +} +#endif /* CONFIG_DM_ETH */ + +#ifndef CONFIG_DM_ETH static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg) { struct fsl_enet_mac *mac; @@ -678,22 +765,75 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg) return 0; } +#else /* CONFIG_DM_ETH */ +static int fm_eth_init_mac(struct fm_eth *fm_eth, void *reg) +{ +#ifndef CONFIG_SYS_FMAN_V3 + void *mdio; +#endif + + fm_eth->mac = kzalloc(sizeof(*fm_eth->mac), GFP_KERNEL); + if (!fm_eth->mac) + return -ENOMEM; -static int init_phy(struct eth_device *dev) +#ifndef CONFIG_SYS_FMAN_V3 + mdio = fman_mdio(fm_eth->dev->parent, fm_eth->mac_type, fm_eth->num); + debug("MDIO %d @ %p\n", fm_eth->num, mdio); +#endif + + switch (fm_eth->mac_type) { +#ifdef CONFIG_SYS_FMAN_V3 + case FM_MEMAC: + init_memac(fm_eth->mac, reg, NULL, MAX_RXBUF_LEN); + break; +#else + case FM_DTSEC: + init_dtsec(fm_eth->mac, reg, mdio, MAX_RXBUF_LEN); + break; + case FM_TGEC: + init_tgec(fm_eth->mac, reg, mdio, MAX_RXBUF_LEN); + break; +#endif + } + + return 0; +} +#endif /* CONFIG_DM_ETH */ + +static int init_phy(struct fm_eth *fm_eth) { - struct fm_eth *fm_eth = dev->priv; #ifdef CONFIG_PHYLIB + u32 supported = PHY_GBIT_FEATURES; +#ifndef CONFIG_DM_ETH struct phy_device *phydev = NULL; - u32 supported; +#endif + + if (fm_eth->type == FM_ETH_10G_E) + supported = PHY_10G_FEATURES; + if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII_2500) + supported |= SUPPORTED_2500baseX_Full; #endif if (fm_eth->type == FM_ETH_1G_E) - dtsec_init_phy(dev); + dtsec_init_phy(fm_eth); +#ifdef CONFIG_DM_ETH +#ifdef CONFIG_PHYLIB +#ifdef CONFIG_DM_MDIO + fm_eth->phydev = dm_eth_phy_connect(fm_eth->dev); + if (!fm_eth->phydev) + return -ENODEV; +#endif + fm_eth->phydev->advertising &= supported; + fm_eth->phydev->supported &= supported; + + phy_config(fm_eth->phydev); +#endif +#else /* CONFIG_DM_ETH */ #ifdef CONFIG_PHYLIB if (fm_eth->bus) { - phydev = phy_connect(fm_eth->bus, fm_eth->phyaddr, dev, - fm_eth->enet_if); + phydev = phy_connect(fm_eth->bus, fm_eth->phyaddr, fm_eth->dev, + fm_eth->enet_if); if (!phydev) { printf("Failed to connect\n"); return -1; @@ -711,7 +851,7 @@ static int init_phy(struct eth_device *dev) } else { supported = SUPPORTED_10000baseT_Full; - if (tgec_is_fibre(dev)) + if (tgec_is_fibre(fm_eth)) phydev->port = PORT_FIBRE; } @@ -722,10 +862,11 @@ static int init_phy(struct eth_device *dev) phy_config(phydev); #endif - +#endif /* CONFIG_DM_ETH */ return 0; } +#ifndef CONFIG_DM_ETH int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info) { struct eth_device *dev; @@ -784,7 +925,7 @@ int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info) if (ret) return ret; - init_phy(dev); + init_phy(fm_eth); /* clear the ethernet address */ for (i = 0; i < 6; i++) @@ -793,3 +934,201 @@ int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info) return 0; } +#else /* CONFIG_DM_ETH */ +#ifdef CONFIG_PHYLIB +phy_interface_t fman_read_sys_if(struct udevice *dev) +{ + const char *if_str; + + if_str = ofnode_read_string(dev->node, "phy-connection-type"); + debug("MAC system interface mode %s\n", if_str); + + return phy_get_interface_by_name(if_str); +} +#endif + +static int fm_eth_bind(struct udevice *dev) +{ + char mac_name[11]; + u32 fm, num; + + if (ofnode_read_u32(ofnode_get_parent(dev->node), "cell-index", &fm)) { + printf("FMan node property cell-index missing\n"); + return -EINVAL; + } + + if (dev && dev_read_u32(dev, "cell-index", &num)) { + printf("FMan MAC node property cell-index missing\n"); + return -EINVAL; + } + + sprintf(mac_name, "fm%d-mac%d", fm + 1, num + 1); + device_set_name(dev, mac_name); + + debug("%s - binding %s\n", __func__, mac_name); + + return 0; +} + +static struct udevice *fm_get_internal_mdio(struct udevice *dev) +{ + struct ofnode_phandle_args phandle = {.node = ofnode_null()}; + struct udevice *mdiodev; + + if (dev_read_phandle_with_args(dev, "pcsphy-handle", NULL, + 0, 0, &phandle) || + !ofnode_valid(phandle.node)) { + if (dev_read_phandle_with_args(dev, "tbi-handle", NULL, + 0, 0, &phandle) || + !ofnode_valid(phandle.node)) { + printf("Issue reading pcsphy-handle/tbi-handle for MAC %s\n", + dev->name); + return NULL; + } + } + + if (uclass_get_device_by_ofnode(UCLASS_MDIO, + ofnode_get_parent(phandle.node), + &mdiodev)) { + printf("can't find MDIO bus for node %s\n", + ofnode_get_name(ofnode_get_parent(phandle.node))); + return NULL; + } + debug("Found internal MDIO bus %p\n", mdiodev); + + return mdiodev; +} + +static int fm_eth_probe(struct udevice *dev) +{ + struct fm_eth *fm_eth = (struct fm_eth *)dev->priv; + struct ofnode_phandle_args args; + void *reg; + int ret, index; + + debug("%s enter for dev %p fm_eth %p - %s\n", __func__, dev, fm_eth, + (dev) ? dev->name : "-"); + + if (fm_eth->dev) { + printf("%s already probed, exit\n", (dev) ? dev->name : "-"); + return 0; + } + + fm_eth->dev = dev; + fm_eth->fm_index = fman_id(dev->parent); + reg = (void *)(uintptr_t)dev_read_addr(dev); + fm_eth->mac_type = dev_get_driver_data(dev); +#ifdef CONFIG_PHYLIB + fm_eth->enet_if = fman_read_sys_if(dev); +#else + fm_eth->enet_if = PHY_INTERFACE_MODE_SGMII; + printf("%s: warning - unable to determine interface type\n", __func__); +#endif + switch (fm_eth->mac_type) { +#ifndef CONFIG_SYS_FMAN_V3 + case FM_TGEC: + fm_eth->type = FM_ETH_10G_E; + break; + case FM_DTSEC: +#else + case FM_MEMAC: + /* default to 1G, 10G is indicated by port property in dts */ +#endif + fm_eth->type = FM_ETH_1G_E; + break; + } + + if (dev_read_u32(dev, "cell-index", &fm_eth->num)) { + printf("FMan MAC node property cell-index missing\n"); + return -EINVAL; + } + + if (dev_read_phandle_with_args(dev, "fsl,fman-ports", NULL, + 0, 0, &args)) + goto ports_ref_failure; + index = ofnode_read_u32_default(args.node, "cell-index", 0); + if (index <= 0) + goto ports_ref_failure; + fm_eth->rx_port = fman_port(dev->parent, index); + + if (ofnode_read_bool(args.node, "fsl,fman-10g-port")) + fm_eth->type = FM_ETH_10G_E; + + if (dev_read_phandle_with_args(dev, "fsl,fman-ports", NULL, + 0, 1, &args)) + goto ports_ref_failure; + index = ofnode_read_u32_default(args.node, "cell-index", 0); + if (index <= 0) + goto ports_ref_failure; + fm_eth->tx_port = fman_port(dev->parent, index); + + /* set the ethernet max receive length */ + fm_eth->max_rx_len = MAX_RXBUF_LEN; + + switch (fm_eth->enet_if) { + case PHY_INTERFACE_MODE_QSGMII: + /* all PCS blocks are accessed on one controller */ + if (fm_eth->num != 0) + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_SGMII_2500: + fm_eth->pcs_mdio = fm_get_internal_mdio(dev); + break; + default: + break; + } + + /* init global mac structure */ + ret = fm_eth_init_mac(fm_eth, reg); + if (ret) + return ret; + + /* startup the FM im */ + ret = fm_eth_startup(fm_eth); + + if (!ret) + ret = init_phy(fm_eth); + + return ret; + +ports_ref_failure: + printf("Issue reading fsl,fman-ports for MAC %s\n", dev->name); + return -ENOENT; +} + +static int fm_eth_remove(struct udevice *dev) +{ + return 0; +} + +static const struct eth_ops fm_eth_ops = { + .start = fm_eth_open, + .send = fm_eth_send, + .recv = fm_eth_recv, + .free_pkt = fm_eth_free_pkt, + .stop = fm_eth_halt, +}; + +static const struct udevice_id fm_eth_ids[] = { +#ifdef CONFIG_SYS_FMAN_V3 + { .compatible = "fsl,fman-memac", .data = FM_MEMAC }, +#else + { .compatible = "fsl,fman-dtsec", .data = FM_DTSEC }, + { .compatible = "fsl,fman-xgec", .data = FM_TGEC }, +#endif + {} +}; + +U_BOOT_DRIVER(eth_fman) = { + .name = "eth_fman", + .id = UCLASS_ETH, + .of_match = fm_eth_ids, + .bind = fm_eth_bind, + .probe = fm_eth_probe, + .remove = fm_eth_remove, + .ops = &fm_eth_ops, + .priv_auto_alloc_size = sizeof(struct fm_eth), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c index 7a081b9d03..8ab1816395 100644 --- a/drivers/net/fm/fm.c +++ b/drivers/net/fm/fm.c @@ -9,6 +9,9 @@ #include <asm/io.h> #include <linux/errno.h> #include <u-boot/crc.h> +#ifdef CONFIG_DM_ETH +#include <dm.h> +#endif #include "fm.h" #include <fsl_qe.h> /* For struct qe_firmware */ @@ -529,3 +532,80 @@ int fm_init_common(int index, struct ccsr_fman *reg) return fm_init_bmi(index, ®->fm_bmi_common); } #endif + +#ifdef CONFIG_DM_ETH +struct fman_priv { + struct ccsr_fman *reg; + unsigned int fman_id; +}; + +static const struct udevice_id fman_ids[] = { + { .compatible = "fsl,fman" }, + {} +}; + +static int fman_probe(struct udevice *dev) +{ + struct fman_priv *priv = dev_get_priv(dev); + + priv->reg = (struct ccsr_fman *)(uintptr_t)dev_read_addr(dev); + + if (dev_read_u32(dev, "cell-index", &priv->fman_id)) { + printf("FMan node property cell-index missing\n"); + return -EINVAL; + } + + return fm_init_common(priv->fman_id, priv->reg); +} + +static int fman_remove(struct udevice *dev) +{ + return 0; +} + +int fman_id(struct udevice *dev) +{ + struct fman_priv *priv = dev_get_priv(dev); + + return priv->fman_id; +} + +void *fman_port(struct udevice *dev, int num) +{ + struct fman_priv *priv = dev_get_priv(dev); + + return &priv->reg->port[num - 1].fm_bmi; +} + +void *fman_mdio(struct udevice *dev, enum fm_mac_type type, int num) +{ + struct fman_priv *priv = dev_get_priv(dev); + void *res = NULL; + + switch (type) { +#ifdef CONFIG_SYS_FMAN_V3 + case FM_MEMAC: + res = &priv->reg->memac[num].fm_memac_mdio; + break; +#else + case FM_DTSEC: + res = &priv->reg->mac_1g[num].fm_mdio.miimcfg; + break; + case FM_TGEC: + res = &priv->reg->mac_10g[num].fm_10gec_mdio; + break; +#endif + } + return res; +} + +U_BOOT_DRIVER(fman) = { + .name = "fman", + .id = UCLASS_SIMPLE_BUS, + .of_match = fman_ids, + .probe = fman_probe, + .remove = fman_remove, + .priv_auto_alloc_size = sizeof(struct fman_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h index e5deaf52c5..2379b3a11c 100644 --- a/drivers/net/fm/fm.h +++ b/drivers/net/fm/fm.h @@ -57,6 +57,18 @@ struct fm_port_bd { #define TxBD_READY 0x8000 #define TxBD_LAST BD_LAST +#ifdef CONFIG_DM_ETH +enum fm_mac_type { +#ifdef CONFIG_SYS_FMAN_V3 + FM_MEMAC, +#else + FM_DTSEC, + FM_TGEC, +#endif +}; +#endif + +/* Fman ethernet private struct */ /* Rx/Tx queue descriptor */ struct fm_port_qd { u16 gen; @@ -101,6 +113,11 @@ int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info); phy_interface_t fman_port_enet_if(enum fm_port port); void fman_disable_port(enum fm_port port); void fman_enable_port(enum fm_port port); +int fman_id(struct udevice *dev); +void *fman_port(struct udevice *dev, int num); +#ifdef CONFIG_DM_ETH +void *fman_mdio(struct udevice *dev, enum fm_mac_type type, int num); +#endif struct fsl_enet_mac { void *base; /* MAC controller registers base address */ @@ -126,7 +143,13 @@ struct fm_eth { struct mii_dev *bus; struct phy_device *phydev; int phyaddr; +#ifndef CONFIG_DM_ETH struct eth_device *dev; +#else + enum fm_mac_type mac_type; + struct udevice *dev; + struct udevice *pcs_mdio; +#endif int max_rx_len; struct fm_port_global_pram *rx_pram; /* Rx parameter table */ struct fm_port_global_pram *tx_pram; /* Tx parameter table */ diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c index f896e80b6d..8669d21afb 100644 --- a/drivers/net/fm/init.c +++ b/drivers/net/fm/init.c @@ -15,6 +15,7 @@ #include "fm.h" +#ifndef CONFIG_DM_ETH struct fm_eth_info fm_info[] = { #if (CONFIG_SYS_NUM_FM1_DTSEC >= 1) FM_DTSEC_INFO_INITIALIZER(1, 1), @@ -380,3 +381,4 @@ int is_qsgmii_riser_card(struct mii_dev *bus, int phy_base_addr, return 0; } +#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/fm/memac.c b/drivers/net/fm/memac.c index bed8f14aee..77ea083782 100644 --- a/drivers/net/fm/memac.c +++ b/drivers/net/fm/memac.c @@ -137,6 +137,7 @@ static void memac_set_interface_mode(struct fsl_enet_mac *mac, void init_memac(struct fsl_enet_mac *mac, void *base, void *phyregs, int max_rx_len) { + debug("%s: @ %p, mdio @ %p\n", __func__, base, phyregs); mac->base = base; mac->phyregs = phyregs; mac->max_rx_len = max_rx_len; diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c index c2ef1b4e73..4cbfbc70ab 100644 --- a/drivers/net/fm/memac_phy.c +++ b/drivers/net/fm/memac_phy.c @@ -22,6 +22,12 @@ #define memac_setbits_32(a, v) setbits_be32(a, v) #endif +#ifdef CONFIG_DM_ETH +struct fm_mdio_priv { + struct memac_mdio_controller *regs; +}; +#endif + static u32 memac_in_32(u32 *reg) { #ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN @@ -39,10 +45,23 @@ static u32 memac_in_32(u32 *reg) int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr, int regnum, u16 value) { + struct memac_mdio_controller *regs; u32 mdio_ctl; - struct memac_mdio_controller *regs = bus->priv; u32 c45 = 1; /* Default to 10G interface */ +#ifndef CONFIG_DM_ETH + regs = bus->priv; +#else + struct fm_mdio_priv *priv; + + if (!bus->priv) + return -EINVAL; + priv = dev_get_priv(bus->priv); + regs = priv->regs; + debug("memac_mdio_write(regs %p, port %d, dev %d, reg %d, val %#x)\n", + regs, port_addr, dev_addr, regnum, value); +#endif + if (dev_addr == MDIO_DEVAD_NONE) { c45 = 0; /* clause 22 */ dev_addr = regnum & 0x1f; @@ -84,13 +103,26 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr, int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr, int regnum) { + struct memac_mdio_controller *regs; u32 mdio_ctl; - struct memac_mdio_controller *regs = bus->priv; u32 c45 = 1; +#ifndef CONFIG_DM_ETH + regs = bus->priv; +#else + struct fm_mdio_priv *priv; + + if (!bus->priv) + return -EINVAL; + priv = dev_get_priv(bus->priv); + regs = priv->regs; +#endif + if (dev_addr == MDIO_DEVAD_NONE) { +#ifndef CONFIG_DM_ETH if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME)) return 0xffff; +#endif c45 = 0; /* clause 22 */ dev_addr = regnum & 0x1f; memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); @@ -133,6 +165,7 @@ int memac_mdio_reset(struct mii_dev *bus) return 0; } +#ifndef CONFIG_DM_ETH int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info) { struct mii_dev *bus = mdio_alloc(); @@ -167,3 +200,105 @@ int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info) return mdio_register(bus); } + +#else /* CONFIG_DM_ETH */ +#if defined(CONFIG_PHYLIB) && defined(CONFIG_DM_MDIO) +static int fm_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : + NULL; + + if (pdata && pdata->mii_bus) + return memac_mdio_read(pdata->mii_bus, addr, devad, reg); + + return -1; +} + +static int fm_mdio_write(struct udevice *dev, int addr, int devad, int reg, + u16 val) +{ + struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : + NULL; + + if (pdata && pdata->mii_bus) + return memac_mdio_write(pdata->mii_bus, addr, devad, reg, val); + + return -1; +} + +static int fm_mdio_reset(struct udevice *dev) +{ + struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : + NULL; + + if (pdata && pdata->mii_bus) + return memac_mdio_reset(pdata->mii_bus); + + return -1; +} + +static const struct mdio_ops fm_mdio_ops = { + .read = fm_mdio_read, + .write = fm_mdio_write, + .reset = fm_mdio_reset, +}; + +static const struct udevice_id fm_mdio_ids[] = { + { .compatible = "fsl,fman-memac-mdio" }, + {} +}; + +static int fm_mdio_probe(struct udevice *dev) +{ + struct fm_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL; + struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : + NULL; + + if (!dev) { + printf("%s dev = NULL\n", __func__); + return -1; + } + if (!priv) { + printf("dev_get_priv(dev %p) = NULL\n", dev); + return -1; + } + priv->regs = (void *)(uintptr_t)dev_read_addr(dev); + debug("%s priv %p @ regs %p, pdata %p\n", __func__, + priv, priv->regs, pdata); + + /* + * On some platforms like B4860, default value of MDIO_CLK_DIV bits + * in mdio_stat(mdio_cfg) register generates MDIO clock too high + * (much higher than 2.5MHz), violating the IEEE specs. + * On other platforms like T1040, default value of MDIO_CLK_DIV bits + * is zero, so MDIO clock is disabled. + * So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to + * be properly initialized. + * The default NEG bit should be '1' as per FMANv3 RM, but on platforms + * like T2080QDS, this bit default is '0', which leads to MDIO failure + * on XAUI PHY, so set this bit definitely. + */ + if (priv && priv->regs && priv->regs->mdio_stat) + memac_setbits_32(&priv->regs->mdio_stat, + MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); + + return 0; +} + +static int fm_mdio_remove(struct udevice *dev) +{ + return 0; +} + +U_BOOT_DRIVER(fman_mdio) = { + .name = "fman_mdio", + .id = UCLASS_MDIO, + .of_match = fm_mdio_ids, + .probe = fm_mdio_probe, + .remove = fm_mdio_remove, + .ops = &fm_mdio_ops, + .priv_auto_alloc_size = sizeof(struct fm_mdio_priv), + .platdata_auto_alloc_size = sizeof(struct mdio_perdev_priv), +}; +#endif /* CONFIG_PHYLIB && CONFIG_DM_MDIO */ +#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 07bbcc9b23..fee372968a 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -174,9 +174,21 @@ enum mc_fixup_type { }; static int mc_fixup_mac_addr(void *blob, int nodeoffset, +#ifdef CONFIG_DM_ETH + const char *propname, struct udevice *eth_dev, +#else const char *propname, struct eth_device *eth_dev, +#endif enum mc_fixup_type type) { +#ifdef CONFIG_DM_ETH + struct eth_pdata *plat = dev_get_platdata(eth_dev); + unsigned char *enetaddr = plat->enetaddr; + int eth_index = eth_dev->seq; +#else + unsigned char *enetaddr = eth_dev->enetaddr; + int eth_index = eth_dev->index; +#endif int err = 0, len = 0, size, i; unsigned char env_enetaddr[ARP_HLEN]; unsigned int enetaddr_32[ARP_HLEN]; @@ -184,23 +196,22 @@ static int mc_fixup_mac_addr(void *blob, int nodeoffset, switch (type) { case MC_FIXUP_DPL: - /* DPL likes its addresses on 32 * ARP_HLEN bits */ - for (i = 0; i < ARP_HLEN; i++) - enetaddr_32[i] = cpu_to_fdt32(eth_dev->enetaddr[i]); - val = enetaddr_32; - len = sizeof(enetaddr_32); - break; - + /* DPL likes its addresses on 32 * ARP_HLEN bits */ + for (i = 0; i < ARP_HLEN; i++) + enetaddr_32[i] = cpu_to_fdt32(enetaddr[i]); + val = enetaddr_32; + len = sizeof(enetaddr_32); + break; case MC_FIXUP_DPC: - val = eth_dev->enetaddr; - len = ARP_HLEN; - break; + val = enetaddr; + len = ARP_HLEN; + break; } /* MAC address property present */ if (fdt_get_property(blob, nodeoffset, propname, NULL)) { /* u-boot MAC addr randomly assigned - leave the present one */ - if (!eth_env_get_enetaddr_by_index("eth", eth_dev->index, + if (!eth_env_get_enetaddr_by_index("eth", eth_index, env_enetaddr)) return err; } else { @@ -250,7 +261,11 @@ const char *dpl_get_connection_endpoint(void *blob, char *endpoint) } static int mc_fixup_dpl_mac_addr(void *blob, int dpmac_id, +#ifdef CONFIG_DM_ETH + struct udevice *eth_dev) +#else struct eth_device *eth_dev) +#endif { int objoff = fdt_path_offset(blob, "/objects"); int dpmacoff = -1, dpnioff = -1; @@ -334,7 +349,11 @@ void fdt_fsl_mc_fixup_iommu_map_entry(void *blob) } static int mc_fixup_dpc_mac_addr(void *blob, int dpmac_id, +#ifdef CONFIG_DM_ETH + struct udevice *eth_dev) +#else struct eth_device *eth_dev) +#endif { int nodeoffset = fdt_path_offset(blob, "/board_info/ports"), noff; int err = 0; @@ -377,8 +396,13 @@ static int mc_fixup_dpc_mac_addr(void *blob, int dpmac_id, static int mc_fixup_mac_addrs(void *blob, enum mc_fixup_type type) { int i, err = 0, ret = 0; - char ethname[ETH_NAME_LEN]; +#ifdef CONFIG_DM_ETH +#define ETH_NAME_LEN 20 + struct udevice *eth_dev; +#else struct eth_device *eth_dev; +#endif + char ethname[ETH_NAME_LEN]; for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) { /* port not enabled */ diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c new file mode 100644 index 0000000000..6d8332d19a --- /dev/null +++ b/drivers/net/fsl_ls_mdio.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <miiphy.h> +#include <asm/io.h> +#include <fsl_memac.h> + +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN +#define memac_out_32(a, v) out_le32(a, v) +#define memac_clrbits_32(a, v) clrbits_le32(a, v) +#define memac_setbits_32(a, v) setbits_le32(a, v) +#else +#define memac_out_32(a, v) out_be32(a, v) +#define memac_clrbits_32(a, v) clrbits_be32(a, v) +#define memac_setbits_32(a, v) setbits_be32(a, v) +#endif + +static u32 memac_in_32(u32 *reg) +{ +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN + return in_le32(reg); +#else + return in_be32(reg); +#endif +} + +struct fsl_ls_mdio_priv { + void *regs_base; +}; + +static u32 fsl_ls_mdio_setup_operation(struct udevice *dev, int addr, int devad, + int reg) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + u32 mdio_ctl; + u32 c45 = 1; + + regs = (struct memac_mdio_controller *)(priv->regs_base); + if (devad == MDIO_DEVAD_NONE) { + c45 = 0; /* clause 22 */ + devad = reg & 0x1f; + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); + } else { + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); + } + + /* Wait till the bus is free */ + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) + ; + + /* Set the Port and Device Addrs */ + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | MDIO_CTL_DEV_ADDR(devad); + memac_out_32(®s->mdio_ctl, mdio_ctl); + + /* Set the register address */ + if (c45) + memac_out_32(®s->mdio_addr, reg & 0xffff); + + /* Wait till the bus is free */ + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) + ; + + return mdio_ctl; +} + +static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, + int devad, int reg) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + u32 mdio_ctl; + + regs = (struct memac_mdio_controller *)(priv->regs_base); + mdio_ctl = fsl_ls_mdio_setup_operation(dev, addr, devad, reg); + + /* Initiate the read */ + mdio_ctl |= MDIO_CTL_READ; + memac_out_32(®s->mdio_ctl, mdio_ctl); + + /* Wait till the MDIO write is complete */ + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) + ; + + /* Return all Fs if nothing was there */ + if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) + return 0xffff; + + return memac_in_32(®s->mdio_data) & 0xffff; +} + +static int dm_fsl_ls_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 val) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + + regs = (struct memac_mdio_controller *)(priv->regs_base); + fsl_ls_mdio_setup_operation(dev, addr, devad, reg); + + /* Write the value to the register */ + memac_out_32(®s->mdio_data, MDIO_DATA(val)); + + /* Wait till the MDIO write is complete */ + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) + ; + + return 0; +} + +static const struct mdio_ops fsl_ls_mdio_ops = { + .read = dm_fsl_ls_mdio_read, + .write = dm_fsl_ls_mdio_write, +}; + +static int fsl_ls_mdio_probe(struct udevice *dev) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + + priv->regs_base = dev_read_addr_ptr(dev); + regs = (struct memac_mdio_controller *)(priv->regs_base); + + memac_setbits_32(®s->mdio_stat, + MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); + + return 0; +} + +static const struct udevice_id fsl_ls_mdio_of_ids[] = { + { .compatible = "fsl,ls-mdio" }, +}; + +U_BOOT_DRIVER(fsl_ls_mdio) = { + .name = "fsl_ls_mdio", + .id = UCLASS_MDIO, + .of_match = fsl_ls_mdio_of_ids, + .probe = fsl_ls_mdio_probe, + .ops = &fsl_ls_mdio_ops, + .priv_auto_alloc_size = sizeof(struct fsl_ls_mdio_priv), +}; diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index a3b9c152b2..48343dce1c 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -12,6 +12,7 @@ #include <net.h> #include <hwconfig.h> #include <phy.h> +#include <miiphy.h> #include <linux/compat.h> #include <fsl-mc/fsl_dpmac.h> @@ -19,6 +20,19 @@ #include "ldpaa_eth.h" #ifdef CONFIG_PHYLIB +#ifdef CONFIG_DM_ETH +static void init_phy(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + + priv->phy = dm_eth_phy_connect(dev); + + if (!priv->phy) + return; + + phy_config(priv->phy); +} +#else static int init_phy(struct eth_device *dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; @@ -63,6 +77,7 @@ static int init_phy(struct eth_device *dev) return ret; } #endif +#endif #ifdef DEBUG @@ -128,9 +143,15 @@ static void ldpaa_eth_get_dpni_counter(void) } } +#ifdef CONFIG_DM_ETH +static void ldpaa_eth_get_dpmac_counter(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static void ldpaa_eth_get_dpmac_counter(struct eth_device *net_dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; +#endif int err = 0; u64 value; @@ -263,9 +284,16 @@ error: return; } +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_pull_dequeue_rx(struct udevice *dev, + int flags, uchar **packetp) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; +#endif const struct ldpaa_dq *dq; const struct dpaa_fd *fd; int i = 5, err = 0, status; @@ -322,9 +350,15 @@ static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev) return err; } +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_tx(struct udevice *dev, void *buf, int len) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static int ldpaa_eth_tx(struct eth_device *net_dev, void *buf, int len) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; +#endif struct dpaa_fd fd; u64 buffer_start; int data_offset, err; @@ -400,15 +434,33 @@ error: return err; } +static struct phy_device *ldpaa_get_phydev(struct ldpaa_eth_priv *priv) +{ +#ifdef CONFIG_DM_ETH + return priv->phy; +#else +#ifdef CONFIG_PHYLIB + struct phy_device *phydev = NULL; + int phy_num; + + /* start the phy devices one by one and update the dpmac state */ + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); + if (phydev) + return phydev; + } + return NULL; +#endif + return NULL; +#endif +} + static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, struct dpmac_link_state *state) { phy_interface_t enet_if; - int phys_detected; -#ifdef CONFIG_PHYLIB struct phy_device *phydev = NULL; - int err, phy_num; -#endif + int err; /* let's start off with maximum capabilities */ enet_if = wriop_get_enet_if(priv->dpmac_id); @@ -420,39 +472,28 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, state->rate = SPEED_1000; break; } - state->up = 1; - phys_detected = 0; -#ifdef CONFIG_PHYLIB + state->up = 1; state->options |= DPMAC_LINK_OPT_AUTONEG; + phydev = ldpaa_get_phydev(priv); - /* start the phy devices one by one and update the dpmac state */ - for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { - phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); - if (!phydev) - continue; - - phys_detected++; + if (phydev) { err = phy_startup(phydev); if (err) { printf("%s: Could not initialize\n", phydev->dev->name); state->up = 0; - break; - } - if (phydev->link) { + } else if (phydev->link) { state->rate = min(state->rate, (uint32_t)phydev->speed); if (!phydev->duplex) state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; if (!phydev->autoneg) state->options &= ~DPMAC_LINK_OPT_AUTONEG; } else { - /* break out of loop even if one phy is down */ state->up = 0; - break; } } -#endif - if (!phys_detected) + + if (!phydev) state->options &= ~DPMAC_LINK_OPT_AUTONEG; if (!state->up) { @@ -464,9 +505,16 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, return 0; } +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_open(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; +#endif struct dpmac_link_state dpmac_link_state = { 0 }; #ifdef DEBUG struct dpni_link_state link_state; @@ -474,8 +522,13 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) int err = 0; struct dpni_queue d_queue; +#ifdef CONFIG_DM_ETH + if (eth_is_active(dev)) + return 0; +#else if (net_dev->state == ETH_STATE_ACTIVE) return 0; +#endif if (get_mc_boot_status() != 0) { printf("ERROR (MC is not booted)\n"); @@ -515,8 +568,13 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) if (err) goto err_dpni_bind; +#ifdef CONFIG_DM_ETH + err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, plat->enetaddr); +#else err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, net_dev->enetaddr); +#endif if (err) { printf("dpni_add_mac_addr() failed\n"); return err; @@ -589,23 +647,35 @@ err_dpmac_setup: return err; } +#ifdef CONFIG_DM_ETH +static void ldpaa_eth_stop(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static void ldpaa_eth_stop(struct eth_device *net_dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; - int err = 0; -#ifdef CONFIG_PHYLIB - struct phy_device *phydev = NULL; - int phy_num; #endif + struct phy_device *phydev = NULL; + int err = 0; +#ifdef CONFIG_DM_ETH + if (!eth_is_active(dev)) + return; +#else if ((net_dev->state == ETH_STATE_PASSIVE) || (net_dev->state == ETH_STATE_INIT)) return; +#endif #ifdef DEBUG ldpaa_eth_get_dpni_counter(); +#ifdef CONFIG_DM_ETH + ldpaa_eth_get_dpmac_counter(dev); +#else ldpaa_eth_get_dpmac_counter(net_dev); #endif +#endif err = dprc_disconnect(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dprc_handle, &dpmac_endpoint); @@ -628,13 +698,9 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) if (err < 0) printf("dpni_disable() failed\n"); -#ifdef CONFIG_PHYLIB - for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { - phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); - if (phydev) - phy_shutdown(phydev); - } -#endif + phydev = ldpaa_get_phydev(priv); + if (phydev) + phy_shutdown(phydev); /* Free DPBP handle and reset. */ ldpaa_dpbp_free(); @@ -1027,6 +1093,107 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) return 0; } +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_probe(struct udevice *dev) +{ + struct ofnode_phandle_args phandle; + + /* Nothing to do if there is no "phy-handle" in the DTS node */ + if (dev_read_phandle_with_args(dev, "phy-handle", NULL, + 0, 0, &phandle)) { + return 0; + } + + init_phy(dev); + + return 0; +} + +static uint32_t ldpaa_eth_get_dpmac_id(struct udevice *dev) +{ + int port_node = dev_of_offset(dev); + + return fdtdec_get_uint(gd->fdt_blob, port_node, "reg", -1); +} + +static const char *ldpaa_eth_get_phy_mode_str(struct udevice *dev) +{ + int port_node = dev_of_offset(dev); + const char *phy_mode_str; + + phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, + "phy-connection-type", NULL); + if (phy_mode_str) + return phy_mode_str; + + phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL); + return phy_mode_str; +} + +static int ldpaa_eth_bind(struct udevice *dev) +{ + const char *phy_mode_str = NULL; + uint32_t dpmac_id; + char eth_name[16]; + int phy_mode = -1; + + phy_mode_str = ldpaa_eth_get_phy_mode_str(dev); + if (phy_mode_str) + phy_mode = phy_get_interface_by_name(phy_mode_str); + if (phy_mode == -1) { + dev_err(dev, "incorrect phy mode\n"); + return -EINVAL; + } + + dpmac_id = ldpaa_eth_get_dpmac_id(dev); + if (dpmac_id == -1) { + dev_err(dev, "missing reg field from the dpmac node\n"); + return -EINVAL; + } + + sprintf(eth_name, "DPMAC%d@%s", dpmac_id, phy_mode_str); + device_set_name(dev, eth_name); + + return 0; +} + +static int ldpaa_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + const char *phy_mode_str; + + priv->dpmac_id = ldpaa_eth_get_dpmac_id(dev); + phy_mode_str = ldpaa_eth_get_phy_mode_str(dev); + priv->phy_mode = phy_get_interface_by_name(phy_mode_str); + + return 0; +} + +static const struct eth_ops ldpaa_eth_ops = { + .start = ldpaa_eth_open, + .send = ldpaa_eth_tx, + .recv = ldpaa_eth_pull_dequeue_rx, + .stop = ldpaa_eth_stop, +}; + +static const struct udevice_id ldpaa_eth_of_ids[] = { + { .compatible = "fsl,qoriq-mc-dpmac" }, +}; + +U_BOOT_DRIVER(ldpaa_eth) = { + .name = "ldpaa_eth", + .id = UCLASS_ETH, + .of_match = ldpaa_eth_of_ids, + .ofdata_to_platdata = ldpaa_eth_ofdata_to_platdata, + .bind = ldpaa_eth_bind, + .probe = ldpaa_eth_probe, + .ops = &ldpaa_eth_ops, + .priv_auto_alloc_size = sizeof(struct ldpaa_eth_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +#else + static int ldpaa_eth_netdev_init(struct eth_device *net_dev, phy_interface_t enet_if) { @@ -1099,3 +1266,4 @@ err_netdev_init: return err; } +#endif diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.h b/drivers/net/ldpaa_eth/ldpaa_eth.h index 3f9154b5bb..e90513e56f 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.h +++ b/drivers/net/ldpaa_eth/ldpaa_eth.h @@ -116,7 +116,13 @@ struct ldpaa_fas { LDPAA_ETH_FAS_TIDE) struct ldpaa_eth_priv { +#ifdef CONFIG_DM_ETH + struct phy_device *phy; + int phy_mode; + bool started; +#else struct eth_device *net_dev; +#endif uint32_t dpmac_id; uint16_t dpmac_handle; |