Skip to content

Commit ebfcb23

Browse files
claudiu-mdavem330
authored andcommitted
enetc: Add ENETC PF level external MDIO support
Each ENETC PF has its own MDIO interface, the corresponding MDIO registers are mapped in the ENETC's Port register block. The current patch adds a driver for these PF level MDIO buses, so that each PF can manage directly its own external link. Signed-off-by: Alex Marginean <[email protected]> Signed-off-by: Claudiu Manoil <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0c80540 commit ebfcb23

File tree

4 files changed

+219
-1
lines changed

4 files changed

+219
-1
lines changed

drivers/net/ethernet/freescale/enetc/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
3-
fsl-enetc-$(CONFIG_FSL_ENETC) += enetc.o enetc_cbdr.o enetc_ethtool.o
3+
fsl-enetc-$(CONFIG_FSL_ENETC) += enetc.o enetc_cbdr.o enetc_ethtool.o \
4+
enetc_mdio.o
45
fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
56
fsl-enetc-objs := enetc_pf.o $(fsl-enetc-y)
67

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2+
/* Copyright 2019 NXP */
3+
4+
#include <linux/mdio.h>
5+
#include <linux/of_mdio.h>
6+
#include <linux/iopoll.h>
7+
#include <linux/of.h>
8+
9+
#include "enetc_pf.h"
10+
11+
struct enetc_mdio_regs {
12+
u32 mdio_cfg; /* MDIO configuration and status */
13+
u32 mdio_ctl; /* MDIO control */
14+
u32 mdio_data; /* MDIO data */
15+
u32 mdio_addr; /* MDIO address */
16+
};
17+
18+
#define bus_to_enetc_regs(bus) (struct enetc_mdio_regs __iomem *)((bus)->priv)
19+
20+
#define ENETC_MDIO_REG_OFFSET 0x1c00
21+
#define ENETC_MDC_DIV 258
22+
23+
#define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8)
24+
#define MDIO_CFG_BSY BIT(0)
25+
#define MDIO_CFG_RD_ER BIT(1)
26+
#define MDIO_CFG_ENC45 BIT(6)
27+
/* external MDIO only - driven on neg MDC edge */
28+
#define MDIO_CFG_NEG BIT(23)
29+
30+
#define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f)
31+
#define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
32+
#define MDIO_CTL_READ BIT(15)
33+
#define MDIO_DATA(x) ((x) & 0xffff)
34+
35+
#define TIMEOUT 1000
36+
static int enetc_mdio_wait_complete(struct enetc_mdio_regs __iomem *regs)
37+
{
38+
u32 val;
39+
40+
return readx_poll_timeout(enetc_rd_reg, &regs->mdio_cfg, val,
41+
!(val & MDIO_CFG_BSY), 10, 10 * TIMEOUT);
42+
}
43+
44+
static int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
45+
u16 value)
46+
{
47+
struct enetc_mdio_regs __iomem *regs = bus_to_enetc_regs(bus);
48+
u32 mdio_ctl, mdio_cfg;
49+
u16 dev_addr;
50+
int ret;
51+
52+
mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
53+
if (regnum & MII_ADDR_C45) {
54+
dev_addr = (regnum >> 16) & 0x1f;
55+
mdio_cfg |= MDIO_CFG_ENC45;
56+
} else {
57+
/* clause 22 (ie 1G) */
58+
dev_addr = regnum & 0x1f;
59+
mdio_cfg &= ~MDIO_CFG_ENC45;
60+
}
61+
62+
enetc_wr_reg(&regs->mdio_cfg, mdio_cfg);
63+
64+
ret = enetc_mdio_wait_complete(regs);
65+
if (ret)
66+
return ret;
67+
68+
/* set port and dev addr */
69+
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
70+
enetc_wr_reg(&regs->mdio_ctl, mdio_ctl);
71+
72+
/* set the register address */
73+
if (regnum & MII_ADDR_C45) {
74+
enetc_wr_reg(&regs->mdio_addr, regnum & 0xffff);
75+
76+
ret = enetc_mdio_wait_complete(regs);
77+
if (ret)
78+
return ret;
79+
}
80+
81+
/* write the value */
82+
enetc_wr_reg(&regs->mdio_data, MDIO_DATA(value));
83+
84+
ret = enetc_mdio_wait_complete(regs);
85+
if (ret)
86+
return ret;
87+
88+
return 0;
89+
}
90+
91+
static int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
92+
{
93+
struct enetc_mdio_regs __iomem *regs = bus_to_enetc_regs(bus);
94+
u32 mdio_ctl, mdio_cfg;
95+
u16 dev_addr, value;
96+
int ret;
97+
98+
mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
99+
if (regnum & MII_ADDR_C45) {
100+
dev_addr = (regnum >> 16) & 0x1f;
101+
mdio_cfg |= MDIO_CFG_ENC45;
102+
} else {
103+
dev_addr = regnum & 0x1f;
104+
mdio_cfg &= ~MDIO_CFG_ENC45;
105+
}
106+
107+
enetc_wr_reg(&regs->mdio_cfg, mdio_cfg);
108+
109+
ret = enetc_mdio_wait_complete(regs);
110+
if (ret)
111+
return ret;
112+
113+
/* set port and device addr */
114+
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
115+
enetc_wr_reg(&regs->mdio_ctl, mdio_ctl);
116+
117+
/* set the register address */
118+
if (regnum & MII_ADDR_C45) {
119+
enetc_wr_reg(&regs->mdio_addr, regnum & 0xffff);
120+
121+
ret = enetc_mdio_wait_complete(regs);
122+
if (ret)
123+
return ret;
124+
}
125+
126+
/* initiate the read */
127+
enetc_wr_reg(&regs->mdio_ctl, mdio_ctl | MDIO_CTL_READ);
128+
129+
ret = enetc_mdio_wait_complete(regs);
130+
if (ret)
131+
return ret;
132+
133+
/* return all Fs if nothing was there */
134+
if (enetc_rd_reg(&regs->mdio_cfg) & MDIO_CFG_RD_ER) {
135+
dev_dbg(&bus->dev,
136+
"Error while reading PHY%d reg at %d.%hhu\n",
137+
phy_id, dev_addr, regnum);
138+
return 0xffff;
139+
}
140+
141+
value = enetc_rd_reg(&regs->mdio_data) & 0xffff;
142+
143+
return value;
144+
}
145+
146+
int enetc_mdio_probe(struct enetc_pf *pf)
147+
{
148+
struct device *dev = &pf->si->pdev->dev;
149+
struct enetc_mdio_regs __iomem *regs;
150+
struct device_node *np;
151+
struct mii_bus *bus;
152+
int ret;
153+
154+
bus = mdiobus_alloc_size(sizeof(regs));
155+
if (!bus)
156+
return -ENOMEM;
157+
158+
bus->name = "Freescale ENETC MDIO Bus";
159+
bus->read = enetc_mdio_read;
160+
bus->write = enetc_mdio_write;
161+
bus->parent = dev;
162+
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
163+
164+
/* store the enetc mdio base address for this bus */
165+
regs = pf->si->hw.port + ENETC_MDIO_REG_OFFSET;
166+
bus->priv = regs;
167+
168+
np = of_get_child_by_name(dev->of_node, "mdio");
169+
if (!np) {
170+
dev_err(dev, "MDIO node missing\n");
171+
ret = -EINVAL;
172+
goto err_registration;
173+
}
174+
175+
ret = of_mdiobus_register(bus, np);
176+
if (ret) {
177+
of_node_put(np);
178+
dev_err(dev, "cannot register MDIO bus\n");
179+
goto err_registration;
180+
}
181+
182+
of_node_put(np);
183+
pf->mdio = bus;
184+
185+
return 0;
186+
187+
err_registration:
188+
mdiobus_free(bus);
189+
190+
return ret;
191+
}
192+
193+
void enetc_mdio_remove(struct enetc_pf *pf)
194+
{
195+
if (pf->mdio) {
196+
mdiobus_unregister(pf->mdio);
197+
mdiobus_free(pf->mdio);
198+
}
199+
}

drivers/net/ethernet/freescale/enetc/enetc_pf.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
746746

747747
static int enetc_of_get_phy(struct enetc_ndev_priv *priv)
748748
{
749+
struct enetc_pf *pf = enetc_si_priv(priv->si);
749750
struct device_node *np = priv->dev->of_node;
750751
int err;
751752

@@ -770,12 +771,22 @@ static int enetc_of_get_phy(struct enetc_ndev_priv *priv)
770771
priv->phy_node = of_node_get(np);
771772
}
772773

774+
if (!of_phy_is_fixed_link(np)) {
775+
err = enetc_mdio_probe(pf);
776+
if (err) {
777+
of_node_put(priv->phy_node);
778+
return err;
779+
}
780+
}
781+
773782
priv->if_mode = of_get_phy_mode(np);
774783
if (priv->if_mode < 0) {
775784
dev_err(priv->dev, "missing phy type\n");
776785
of_node_put(priv->phy_node);
777786
if (of_phy_is_fixed_link(np))
778787
of_phy_deregister_fixed_link(np);
788+
else
789+
enetc_mdio_remove(pf);
779790

780791
return -EINVAL;
781792
}
@@ -898,6 +909,7 @@ static void enetc_pf_remove(struct pci_dev *pdev)
898909

899910
unregister_netdev(si->ndev);
900911

912+
enetc_mdio_remove(pf);
901913
enetc_of_put_phy(priv);
902914

903915
enetc_free_msix(priv);

drivers/net/ethernet/freescale/enetc/enetc_pf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@ struct enetc_pf {
4242
char vlan_promisc_simap; /* bitmap of SIs in VLAN promisc mode */
4343
DECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE);
4444
DECLARE_BITMAP(active_vlans, VLAN_N_VID);
45+
46+
struct mii_bus *mdio; /* saved for cleanup */
4547
};
4648

4749
int enetc_msg_psi_init(struct enetc_pf *pf);
4850
void enetc_msg_psi_free(struct enetc_pf *pf);
4951
void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status);
52+
53+
/* MDIO */
54+
int enetc_mdio_probe(struct enetc_pf *pf);
55+
void enetc_mdio_remove(struct enetc_pf *pf);

0 commit comments

Comments
 (0)