xref: /linux/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c (revision 9e676a024fa1fa2bd8150c2d2ba85478280353bc)
180c8c852SWei Fang // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
280c8c852SWei Fang /* Copyright 2024 NXP */
380c8c852SWei Fang 
480c8c852SWei Fang #include <linux/fsl/enetc_mdio.h>
580c8c852SWei Fang #include <linux/of_mdio.h>
680c8c852SWei Fang #include <linux/of_net.h>
780c8c852SWei Fang 
880c8c852SWei Fang #include "enetc_pf_common.h"
980c8c852SWei Fang 
103774409fSWei Fang static void enetc_set_si_hw_addr(struct enetc_pf *pf, int si,
113774409fSWei Fang 				 const u8 *mac_addr)
123774409fSWei Fang {
133774409fSWei Fang 	struct enetc_hw *hw = &pf->si->hw;
143774409fSWei Fang 
153774409fSWei Fang 	pf->ops->set_si_primary_mac(hw, si, mac_addr);
163774409fSWei Fang }
173774409fSWei Fang 
183774409fSWei Fang static void enetc_get_si_hw_addr(struct enetc_pf *pf, int si, u8 *mac_addr)
193774409fSWei Fang {
203774409fSWei Fang 	struct enetc_hw *hw = &pf->si->hw;
213774409fSWei Fang 
223774409fSWei Fang 	pf->ops->get_si_primary_mac(hw, si, mac_addr);
233774409fSWei Fang }
243774409fSWei Fang 
2580c8c852SWei Fang int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
2680c8c852SWei Fang {
2780c8c852SWei Fang 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
283774409fSWei Fang 	struct enetc_pf *pf = enetc_si_priv(priv->si);
2980c8c852SWei Fang 	struct sockaddr *saddr = addr;
3080c8c852SWei Fang 
3180c8c852SWei Fang 	if (!is_valid_ether_addr(saddr->sa_data))
3280c8c852SWei Fang 		return -EADDRNOTAVAIL;
3380c8c852SWei Fang 
3480c8c852SWei Fang 	eth_hw_addr_set(ndev, saddr->sa_data);
353774409fSWei Fang 	enetc_set_si_hw_addr(pf, 0, saddr->sa_data);
3680c8c852SWei Fang 
3780c8c852SWei Fang 	return 0;
3880c8c852SWei Fang }
393774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_pf_set_mac_addr);
4080c8c852SWei Fang 
4180c8c852SWei Fang static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
4280c8c852SWei Fang 				   int si)
4380c8c852SWei Fang {
4480c8c852SWei Fang 	struct device *dev = &pf->si->pdev->dev;
4580c8c852SWei Fang 	u8 mac_addr[ETH_ALEN] = { 0 };
4680c8c852SWei Fang 	int err;
4780c8c852SWei Fang 
4880c8c852SWei Fang 	/* (1) try to get the MAC address from the device tree */
4980c8c852SWei Fang 	if (np) {
5080c8c852SWei Fang 		err = of_get_mac_address(np, mac_addr);
5180c8c852SWei Fang 		if (err == -EPROBE_DEFER)
5280c8c852SWei Fang 			return err;
5380c8c852SWei Fang 	}
5480c8c852SWei Fang 
5580c8c852SWei Fang 	/* (2) bootloader supplied MAC address */
5680c8c852SWei Fang 	if (is_zero_ether_addr(mac_addr))
573774409fSWei Fang 		enetc_get_si_hw_addr(pf, si, mac_addr);
5880c8c852SWei Fang 
5980c8c852SWei Fang 	/* (3) choose a random one */
6080c8c852SWei Fang 	if (is_zero_ether_addr(mac_addr)) {
6180c8c852SWei Fang 		eth_random_addr(mac_addr);
6280c8c852SWei Fang 		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
6380c8c852SWei Fang 			 si, mac_addr);
6480c8c852SWei Fang 	}
6580c8c852SWei Fang 
663774409fSWei Fang 	enetc_set_si_hw_addr(pf, si, mac_addr);
6780c8c852SWei Fang 
6880c8c852SWei Fang 	return 0;
6980c8c852SWei Fang }
7080c8c852SWei Fang 
7180c8c852SWei Fang int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
7280c8c852SWei Fang {
7380c8c852SWei Fang 	int err, i;
7480c8c852SWei Fang 
7580c8c852SWei Fang 	/* The PF might take its MAC from the device tree */
7680c8c852SWei Fang 	err = enetc_setup_mac_address(np, pf, 0);
7780c8c852SWei Fang 	if (err)
7880c8c852SWei Fang 		return err;
7980c8c852SWei Fang 
8080c8c852SWei Fang 	for (i = 0; i < pf->total_vfs; i++) {
8180c8c852SWei Fang 		err = enetc_setup_mac_address(NULL, pf, i + 1);
8280c8c852SWei Fang 		if (err)
8380c8c852SWei Fang 			return err;
8480c8c852SWei Fang 	}
8580c8c852SWei Fang 
8680c8c852SWei Fang 	return 0;
8780c8c852SWei Fang }
883774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
8980c8c852SWei Fang 
9080c8c852SWei Fang void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
9180c8c852SWei Fang 			   const struct net_device_ops *ndev_ops)
9280c8c852SWei Fang {
9380c8c852SWei Fang 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
943774409fSWei Fang 	struct enetc_pf *pf = enetc_si_priv(si);
9580c8c852SWei Fang 
9680c8c852SWei Fang 	SET_NETDEV_DEV(ndev, &si->pdev->dev);
9780c8c852SWei Fang 	priv->ndev = ndev;
9880c8c852SWei Fang 	priv->si = si;
9980c8c852SWei Fang 	priv->dev = &si->pdev->dev;
10080c8c852SWei Fang 	si->ndev = ndev;
10180c8c852SWei Fang 
10280c8c852SWei Fang 	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
10399100d0dSWei Fang 	priv->sysclk_freq = si->drvdata->sysclk_freq;
10493c5d5a0SWei Fang 	priv->max_frags = si->drvdata->max_frags;
10580c8c852SWei Fang 	ndev->netdev_ops = ndev_ops;
10680c8c852SWei Fang 	enetc_set_ethtool_ops(ndev);
10780c8c852SWei Fang 	ndev->watchdog_timeo = 5 * HZ;
10880c8c852SWei Fang 	ndev->max_mtu = ENETC_MAX_MTU;
10980c8c852SWei Fang 
11080c8c852SWei Fang 	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
11180c8c852SWei Fang 			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
11280c8c852SWei Fang 			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
113*c12e82c0SWei Fang 			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
114*c12e82c0SWei Fang 			    NETIF_F_GSO_UDP_L4;
11580c8c852SWei Fang 	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
11680c8c852SWei Fang 			 NETIF_F_HW_VLAN_CTAG_TX |
11780c8c852SWei Fang 			 NETIF_F_HW_VLAN_CTAG_RX |
118*c12e82c0SWei Fang 			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
119*c12e82c0SWei Fang 			 NETIF_F_GSO_UDP_L4;
12080c8c852SWei Fang 	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
12180c8c852SWei Fang 			      NETIF_F_TSO | NETIF_F_TSO6;
12280c8c852SWei Fang 
12399100d0dSWei Fang 	ndev->priv_flags |= IFF_UNICAST_FLT;
12499100d0dSWei Fang 
125d9a093d2SWei Fang 	if (si->drvdata->tx_csum)
126d9a093d2SWei Fang 		priv->active_offloads |= ENETC_F_TXCSUM;
127d9a093d2SWei Fang 
12869797ff8SWei Fang 	if (si->hw_features & ENETC_SI_F_LSO)
12969797ff8SWei Fang 		priv->active_offloads |= ENETC_F_LSO;
13069797ff8SWei Fang 
13199100d0dSWei Fang 	/* TODO: currently, i.MX95 ENETC driver does not support advanced features */
13299100d0dSWei Fang 	if (!is_enetc_rev1(si)) {
13399100d0dSWei Fang 		ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK);
13499100d0dSWei Fang 		goto end;
13599100d0dSWei Fang 	}
13699100d0dSWei Fang 
13780c8c852SWei Fang 	if (si->num_rss)
13880c8c852SWei Fang 		ndev->hw_features |= NETIF_F_RXHASH;
13980c8c852SWei Fang 
14080c8c852SWei Fang 	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
14180c8c852SWei Fang 			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
14280c8c852SWei Fang 			     NETDEV_XDP_ACT_NDO_XMIT_SG;
14380c8c852SWei Fang 
1443774409fSWei Fang 	if (si->hw_features & ENETC_SI_F_PSFP && pf->ops->enable_psfp &&
1453774409fSWei Fang 	    !pf->ops->enable_psfp(priv)) {
14680c8c852SWei Fang 		priv->active_offloads |= ENETC_F_QCI;
14780c8c852SWei Fang 		ndev->features |= NETIF_F_HW_TC;
14880c8c852SWei Fang 		ndev->hw_features |= NETIF_F_HW_TC;
14980c8c852SWei Fang 	}
15080c8c852SWei Fang 
15199100d0dSWei Fang end:
15280c8c852SWei Fang 	/* pick up primary MAC address from SI */
15380c8c852SWei Fang 	enetc_load_primary_mac_addr(&si->hw, ndev);
15480c8c852SWei Fang }
1553774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_pf_netdev_setup);
15680c8c852SWei Fang 
15780c8c852SWei Fang static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
15880c8c852SWei Fang {
15980c8c852SWei Fang 	struct device *dev = &pf->si->pdev->dev;
16080c8c852SWei Fang 	struct enetc_mdio_priv *mdio_priv;
16180c8c852SWei Fang 	struct mii_bus *bus;
16280c8c852SWei Fang 	int err;
16380c8c852SWei Fang 
16480c8c852SWei Fang 	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
16580c8c852SWei Fang 	if (!bus)
16680c8c852SWei Fang 		return -ENOMEM;
16780c8c852SWei Fang 
16880c8c852SWei Fang 	bus->name = "Freescale ENETC MDIO Bus";
16980c8c852SWei Fang 	bus->read = enetc_mdio_read_c22;
17080c8c852SWei Fang 	bus->write = enetc_mdio_write_c22;
17180c8c852SWei Fang 	bus->read_c45 = enetc_mdio_read_c45;
17280c8c852SWei Fang 	bus->write_c45 = enetc_mdio_write_c45;
17380c8c852SWei Fang 	bus->parent = dev;
17480c8c852SWei Fang 	mdio_priv = bus->priv;
17580c8c852SWei Fang 	mdio_priv->hw = &pf->si->hw;
17680c8c852SWei Fang 	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
17780c8c852SWei Fang 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
17880c8c852SWei Fang 
17980c8c852SWei Fang 	err = of_mdiobus_register(bus, np);
18080c8c852SWei Fang 	if (err)
18180c8c852SWei Fang 		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
18280c8c852SWei Fang 
18380c8c852SWei Fang 	pf->mdio = bus;
18480c8c852SWei Fang 
18580c8c852SWei Fang 	return 0;
18680c8c852SWei Fang }
18780c8c852SWei Fang 
18880c8c852SWei Fang static void enetc_mdio_remove(struct enetc_pf *pf)
18980c8c852SWei Fang {
19080c8c852SWei Fang 	if (pf->mdio)
19180c8c852SWei Fang 		mdiobus_unregister(pf->mdio);
19280c8c852SWei Fang }
19380c8c852SWei Fang 
19480c8c852SWei Fang static int enetc_imdio_create(struct enetc_pf *pf)
19580c8c852SWei Fang {
19680c8c852SWei Fang 	struct device *dev = &pf->si->pdev->dev;
19780c8c852SWei Fang 	struct enetc_mdio_priv *mdio_priv;
19880c8c852SWei Fang 	struct phylink_pcs *phylink_pcs;
19980c8c852SWei Fang 	struct mii_bus *bus;
20080c8c852SWei Fang 	int err;
20180c8c852SWei Fang 
2023774409fSWei Fang 	if (!pf->ops->create_pcs) {
2033774409fSWei Fang 		dev_err(dev, "Creating PCS is not supported\n");
2043774409fSWei Fang 
2053774409fSWei Fang 		return -EOPNOTSUPP;
2063774409fSWei Fang 	}
2073774409fSWei Fang 
20880c8c852SWei Fang 	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
20980c8c852SWei Fang 	if (!bus)
21080c8c852SWei Fang 		return -ENOMEM;
21180c8c852SWei Fang 
21280c8c852SWei Fang 	bus->name = "Freescale ENETC internal MDIO Bus";
21380c8c852SWei Fang 	bus->read = enetc_mdio_read_c22;
21480c8c852SWei Fang 	bus->write = enetc_mdio_write_c22;
21580c8c852SWei Fang 	bus->read_c45 = enetc_mdio_read_c45;
21680c8c852SWei Fang 	bus->write_c45 = enetc_mdio_write_c45;
21780c8c852SWei Fang 	bus->parent = dev;
21880c8c852SWei Fang 	bus->phy_mask = ~0;
21980c8c852SWei Fang 	mdio_priv = bus->priv;
22080c8c852SWei Fang 	mdio_priv->hw = &pf->si->hw;
22180c8c852SWei Fang 	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
22280c8c852SWei Fang 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
22380c8c852SWei Fang 
22480c8c852SWei Fang 	err = mdiobus_register(bus);
22580c8c852SWei Fang 	if (err) {
22680c8c852SWei Fang 		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
22780c8c852SWei Fang 		goto free_mdio_bus;
22880c8c852SWei Fang 	}
22980c8c852SWei Fang 
2303774409fSWei Fang 	phylink_pcs = pf->ops->create_pcs(pf, bus);
23180c8c852SWei Fang 	if (IS_ERR(phylink_pcs)) {
23280c8c852SWei Fang 		err = PTR_ERR(phylink_pcs);
23380c8c852SWei Fang 		dev_err(dev, "cannot create lynx pcs (%d)\n", err);
23480c8c852SWei Fang 		goto unregister_mdiobus;
23580c8c852SWei Fang 	}
23680c8c852SWei Fang 
23780c8c852SWei Fang 	pf->imdio = bus;
23880c8c852SWei Fang 	pf->pcs = phylink_pcs;
23980c8c852SWei Fang 
24080c8c852SWei Fang 	return 0;
24180c8c852SWei Fang 
24280c8c852SWei Fang unregister_mdiobus:
24380c8c852SWei Fang 	mdiobus_unregister(bus);
24480c8c852SWei Fang free_mdio_bus:
24580c8c852SWei Fang 	mdiobus_free(bus);
24680c8c852SWei Fang 	return err;
24780c8c852SWei Fang }
24880c8c852SWei Fang 
24980c8c852SWei Fang static void enetc_imdio_remove(struct enetc_pf *pf)
25080c8c852SWei Fang {
2513774409fSWei Fang 	if (pf->pcs && pf->ops->destroy_pcs)
2523774409fSWei Fang 		pf->ops->destroy_pcs(pf->pcs);
25380c8c852SWei Fang 
25480c8c852SWei Fang 	if (pf->imdio) {
25580c8c852SWei Fang 		mdiobus_unregister(pf->imdio);
25680c8c852SWei Fang 		mdiobus_free(pf->imdio);
25780c8c852SWei Fang 	}
25880c8c852SWei Fang }
25980c8c852SWei Fang 
26080c8c852SWei Fang static bool enetc_port_has_pcs(struct enetc_pf *pf)
26180c8c852SWei Fang {
26280c8c852SWei Fang 	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
26380c8c852SWei Fang 		pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
26480c8c852SWei Fang 		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
26580c8c852SWei Fang 		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
26680c8c852SWei Fang }
26780c8c852SWei Fang 
26880c8c852SWei Fang int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
26980c8c852SWei Fang {
27080c8c852SWei Fang 	struct device_node *mdio_np;
27180c8c852SWei Fang 	int err;
27280c8c852SWei Fang 
27380c8c852SWei Fang 	mdio_np = of_get_child_by_name(node, "mdio");
27480c8c852SWei Fang 	if (mdio_np) {
27580c8c852SWei Fang 		err = enetc_mdio_probe(pf, mdio_np);
27680c8c852SWei Fang 
27780c8c852SWei Fang 		of_node_put(mdio_np);
27880c8c852SWei Fang 		if (err)
27980c8c852SWei Fang 			return err;
28080c8c852SWei Fang 	}
28180c8c852SWei Fang 
28280c8c852SWei Fang 	if (enetc_port_has_pcs(pf)) {
28380c8c852SWei Fang 		err = enetc_imdio_create(pf);
28480c8c852SWei Fang 		if (err) {
28580c8c852SWei Fang 			enetc_mdio_remove(pf);
28680c8c852SWei Fang 			return err;
28780c8c852SWei Fang 		}
28880c8c852SWei Fang 	}
28980c8c852SWei Fang 
29080c8c852SWei Fang 	return 0;
29180c8c852SWei Fang }
2923774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_mdiobus_create);
29380c8c852SWei Fang 
29480c8c852SWei Fang void enetc_mdiobus_destroy(struct enetc_pf *pf)
29580c8c852SWei Fang {
29680c8c852SWei Fang 	enetc_mdio_remove(pf);
29780c8c852SWei Fang 	enetc_imdio_remove(pf);
29880c8c852SWei Fang }
2993774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_mdiobus_destroy);
30080c8c852SWei Fang 
30180c8c852SWei Fang int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
30280c8c852SWei Fang 			 const struct phylink_mac_ops *ops)
30380c8c852SWei Fang {
30480c8c852SWei Fang 	struct enetc_pf *pf = enetc_si_priv(priv->si);
30580c8c852SWei Fang 	struct phylink *phylink;
30680c8c852SWei Fang 	int err;
30780c8c852SWei Fang 
30880c8c852SWei Fang 	pf->phylink_config.dev = &priv->ndev->dev;
30980c8c852SWei Fang 	pf->phylink_config.type = PHYLINK_NETDEV;
31080c8c852SWei Fang 	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
31180c8c852SWei Fang 		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
31280c8c852SWei Fang 
31380c8c852SWei Fang 	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
31480c8c852SWei Fang 		  pf->phylink_config.supported_interfaces);
31580c8c852SWei Fang 	__set_bit(PHY_INTERFACE_MODE_SGMII,
31680c8c852SWei Fang 		  pf->phylink_config.supported_interfaces);
31780c8c852SWei Fang 	__set_bit(PHY_INTERFACE_MODE_1000BASEX,
31880c8c852SWei Fang 		  pf->phylink_config.supported_interfaces);
31980c8c852SWei Fang 	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
32080c8c852SWei Fang 		  pf->phylink_config.supported_interfaces);
32180c8c852SWei Fang 	__set_bit(PHY_INTERFACE_MODE_USXGMII,
32280c8c852SWei Fang 		  pf->phylink_config.supported_interfaces);
32380c8c852SWei Fang 	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
32480c8c852SWei Fang 
32580c8c852SWei Fang 	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
32680c8c852SWei Fang 				 pf->if_mode, ops);
32780c8c852SWei Fang 	if (IS_ERR(phylink)) {
32880c8c852SWei Fang 		err = PTR_ERR(phylink);
32980c8c852SWei Fang 		return err;
33080c8c852SWei Fang 	}
33180c8c852SWei Fang 
33280c8c852SWei Fang 	priv->phylink = phylink;
33380c8c852SWei Fang 
33480c8c852SWei Fang 	return 0;
33580c8c852SWei Fang }
3363774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_phylink_create);
33780c8c852SWei Fang 
33880c8c852SWei Fang void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
33980c8c852SWei Fang {
34080c8c852SWei Fang 	phylink_destroy(priv->phylink);
34180c8c852SWei Fang }
3423774409fSWei Fang EXPORT_SYMBOL_GPL(enetc_phylink_destroy);
3433774409fSWei Fang 
3443774409fSWei Fang MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
3453774409fSWei Fang MODULE_LICENSE("Dual BSD/GPL");
346