Commit 1d99534beffea9b8e54a2cf31776cff68c4fc676

Authored by Alex Marginean
Committed by Joe Hershberger
1 parent 120b5ef287

drivers: net: add NXP ENETC MDIO driver

Adds a driver for the MDIO interface currently integrated in LS1028A SoC.
This MDIO interface is shared by multiple ethernet interfaces and is
presented as a stand-alone PCI function on the SoC ECAM.
Ethernet has a functional dependency on MDIO, for simplicity there is a
single config option for both.

Signed-off-by: Alex Marginean <alexm.osslist@gmail.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>

Showing 5 changed files with 229 additions and 2 deletions Side-by-side Diff

... ... @@ -590,7 +590,7 @@
590 590  
591 591 config FSL_ENETC
592 592 bool "NXP ENETC Ethernet controller"
593   - depends on DM_PCI && DM_ETH
  593 + depends on DM_PCI && DM_ETH && DM_MDIO
594 594 help
595 595 This driver supports the NXP ENETC Ethernet controller found on some
596 596 of the NXP SoCs.
drivers/net/Makefile
... ... @@ -79,5 +79,5 @@
79 79 obj-y += mscc_eswitch/
80 80 obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
81 81 obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
82   -obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o
  82 +obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
drivers/net/fsl_enetc.c
... ... @@ -10,6 +10,7 @@
10 10 #include <memalign.h>
11 11 #include <asm/io.h>
12 12 #include <pci.h>
  13 +#include <miiphy.h>
13 14  
14 15 #include "fsl_enetc.h"
15 16  
... ... @@ -38,6 +39,59 @@
38 39 return 0;
39 40 }
40 41  
  42 +/* Configure the actual/external ethernet PHY, if one is found */
  43 +static void enetc_start_phy(struct udevice *dev)
  44 +{
  45 + struct enetc_priv *priv = dev_get_priv(dev);
  46 + struct udevice *miidev;
  47 + struct phy_device *phy;
  48 + u32 phandle, phy_id;
  49 + ofnode phy_node;
  50 + int supported;
  51 +
  52 + if (!ofnode_valid(dev->node)) {
  53 + enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n");
  54 + return;
  55 + }
  56 +
  57 + if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) {
  58 + enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n");
  59 + return;
  60 + }
  61 +
  62 + phy_node = ofnode_get_by_phandle(phandle);
  63 + if (!ofnode_valid(phy_node)) {
  64 + enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n");
  65 + return;
  66 + }
  67 + enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node));
  68 +
  69 + if (ofnode_read_u32(phy_node, "reg", &phy_id)) {
  70 + enetc_dbg(dev,
  71 + "missing reg in PHY node, skipping PHY set-up\n");
  72 + return;
  73 + }
  74 +
  75 + if (uclass_get_device_by_ofnode(UCLASS_MDIO,
  76 + ofnode_get_parent(phy_node),
  77 + &miidev)) {
  78 + enetc_dbg(dev, "can't find MDIO bus for node %s\n",
  79 + ofnode_get_name(ofnode_get_parent(phy_node)));
  80 + return;
  81 + }
  82 +
  83 + phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type);
  84 + if (!phy) {
  85 + enetc_dbg(dev, "dm_mdio_phy_connect returned null\n");
  86 + return;
  87 + }
  88 +
  89 + supported = GENMASK(6, 0); /* speeds up to 1G & AN */
  90 + phy->advertising = phy->supported & supported;
  91 + phy_config(phy);
  92 + phy_startup(phy);
  93 +}
  94 +
41 95 /*
42 96 * Probe ENETC driver:
43 97 * - initialize port and station interface BARs
... ... @@ -248,6 +302,9 @@
248 302 /* setup Tx/Rx buffer descriptors */
249 303 enetc_setup_tx_bdr(dev);
250 304 enetc_setup_rx_bdr(dev);
  305 +
  306 + priv->if_type = PHY_INTERFACE_MODE_NONE;
  307 + enetc_start_phy(dev);
251 308  
252 309 return 0;
253 310 }
drivers/net/fsl_enetc.h
... ... @@ -11,6 +11,7 @@
11 11  
12 12 /* PCI function IDs */
13 13 #define PCI_DEVICE_ID_ENETC_ETH 0xE100
  14 +#define PCI_DEVICE_ID_ENETC_MDIO 0xEE01
14 15  
15 16 /* ENETC Ethernet controller registers */
16 17 /* Station interface register offsets */
... ... @@ -143,6 +144,8 @@
143 144 /* Rx/Tx buffer descriptor rings info */
144 145 struct bd_ring tx_bdr;
145 146 struct bd_ring rx_bdr;
  147 +
  148 + int if_type;
146 149 };
147 150  
148 151 /* register accessors */
... ... @@ -164,6 +167,24 @@
164 167 enetc_read(priv, ENETC_BDR(t, n, off))
165 168 #define enetc_bdr_write(priv, t, n, off, val) \
166 169 enetc_write(priv, ENETC_BDR(t, n, off), val)
  170 +
  171 +/* ENETC external MDIO registers */
  172 +#define ENETC_MDIO_BASE 0x1c00
  173 +#define ENETC_MDIO_CFG 0x00
  174 +#define ENETC_EMDIO_CFG_C22 0x00809508
  175 +#define ENETC_EMDIO_CFG_C45 0x00809548
  176 +#define ENETC_EMDIO_CFG_RD_ER BIT(1)
  177 +#define ENETC_EMDIO_CFG_BSY BIT(0)
  178 +#define ENETC_MDIO_CTL 0x04
  179 +#define ENETC_MDIO_CTL_READ BIT(15)
  180 +#define ENETC_MDIO_DATA 0x08
  181 +#define ENETC_MDIO_STAT 0x0c
  182 +
  183 +#define ENETC_MDIO_READ_ERR 0xffff
  184 +
  185 +struct enetc_mdio_priv {
  186 + void *regs_base;
  187 +};
167 188  
168 189 #endif /* _ENETC_H */
drivers/net/fsl_enetc_mdio.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * ENETC ethernet controller driver
  4 + * Copyright 2019 NXP
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <dm.h>
  9 +#include <errno.h>
  10 +#include <pci.h>
  11 +#include <miiphy.h>
  12 +#include <asm/io.h>
  13 +#include <asm/processor.h>
  14 +#include <miiphy.h>
  15 +
  16 +#include "fsl_enetc.h"
  17 +
  18 +static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
  19 +{
  20 + while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY)
  21 + cpu_relax();
  22 +}
  23 +
  24 +static int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr,
  25 + int devad, int reg)
  26 +{
  27 + if (devad == MDIO_DEVAD_NONE)
  28 + enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
  29 + else
  30 + enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
  31 + enetc_mdio_wait_bsy(priv);
  32 +
  33 + if (devad == MDIO_DEVAD_NONE) {
  34 + enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
  35 + (addr << 5) | reg);
  36 + } else {
  37 + enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
  38 + enetc_mdio_wait_bsy(priv);
  39 +
  40 + enetc_write(priv, ENETC_MDIO_STAT, reg);
  41 + enetc_mdio_wait_bsy(priv);
  42 +
  43 + enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
  44 + (addr << 5) | devad);
  45 + }
  46 +
  47 + enetc_mdio_wait_bsy(priv);
  48 + if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
  49 + return ENETC_MDIO_READ_ERR;
  50 +
  51 + return enetc_read(priv, ENETC_MDIO_DATA);
  52 +}
  53 +
  54 +static int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr,
  55 + int devad, int reg, u16 val)
  56 +{
  57 + if (devad == MDIO_DEVAD_NONE)
  58 + enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
  59 + else
  60 + enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
  61 + enetc_mdio_wait_bsy(priv);
  62 +
  63 + if (devad != MDIO_DEVAD_NONE) {
  64 + enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
  65 + enetc_write(priv, ENETC_MDIO_STAT, reg);
  66 + } else {
  67 + enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
  68 + }
  69 + enetc_mdio_wait_bsy(priv);
  70 +
  71 + enetc_write(priv, ENETC_MDIO_DATA, val);
  72 + enetc_mdio_wait_bsy(priv);
  73 +
  74 + return 0;
  75 +}
  76 +
  77 +/* DM wrappers */
  78 +static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
  79 +{
  80 + struct enetc_mdio_priv *priv = dev_get_priv(dev);
  81 +
  82 + return enetc_mdio_read_priv(priv, addr, devad, reg);
  83 +}
  84 +
  85 +static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
  86 + int reg, u16 val)
  87 +{
  88 + struct enetc_mdio_priv *priv = dev_get_priv(dev);
  89 +
  90 + return enetc_mdio_write_priv(priv, addr, devad, reg, val);
  91 +}
  92 +
  93 +static const struct mdio_ops enetc_mdio_ops = {
  94 + .read = dm_enetc_mdio_read,
  95 + .write = dm_enetc_mdio_write,
  96 +};
  97 +
  98 +static int enetc_mdio_bind(struct udevice *dev)
  99 +{
  100 + char name[16];
  101 + static int eth_num_devices;
  102 +
  103 + /*
  104 + * prefer using PCI function numbers to number interfaces, but these
  105 + * are only available if dts nodes are present. For PCI they are
  106 + * optional, handle that case too. Just in case some nodes are present
  107 + * and some are not, use different naming scheme - enetc-N based on
  108 + * PCI function # and enetc#N based on interface count
  109 + */
  110 + if (ofnode_valid(dev->node))
  111 + sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
  112 + else
  113 + sprintf(name, "emdio#%u", eth_num_devices++);
  114 + device_set_name(dev, name);
  115 +
  116 + return 0;
  117 +}
  118 +
  119 +static int enetc_mdio_probe(struct udevice *dev)
  120 +{
  121 + struct enetc_mdio_priv *priv = dev_get_priv(dev);
  122 +
  123 + priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
  124 + if (!priv->regs_base) {
  125 + enetc_dbg(dev, "failed to map BAR0\n");
  126 + return -EINVAL;
  127 + }
  128 +
  129 + priv->regs_base += ENETC_MDIO_BASE;
  130 +
  131 + dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
  132 +
  133 + return 0;
  134 +}
  135 +
  136 +U_BOOT_DRIVER(enetc_mdio) = {
  137 + .name = "enetc_mdio",
  138 + .id = UCLASS_MDIO,
  139 + .bind = enetc_mdio_bind,
  140 + .probe = enetc_mdio_probe,
  141 + .ops = &enetc_mdio_ops,
  142 + .priv_auto_alloc_size = sizeof(struct enetc_mdio_priv),
  143 +};
  144 +
  145 +static struct pci_device_id enetc_mdio_ids[] = {
  146 + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
  147 +};
  148 +
  149 +U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);