1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Broadcom GENET MDIO routines
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2014-2017 Broadcom
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/acpi.h>
9*4882a593Smuzhiyun #include <linux/types.h>
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/wait.h>
12*4882a593Smuzhiyun #include <linux/mii.h>
13*4882a593Smuzhiyun #include <linux/ethtool.h>
14*4882a593Smuzhiyun #include <linux/bitops.h>
15*4882a593Smuzhiyun #include <linux/netdevice.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/phy.h>
18*4882a593Smuzhiyun #include <linux/phy_fixed.h>
19*4882a593Smuzhiyun #include <linux/brcmphy.h>
20*4882a593Smuzhiyun #include <linux/of.h>
21*4882a593Smuzhiyun #include <linux/of_net.h>
22*4882a593Smuzhiyun #include <linux/of_mdio.h>
23*4882a593Smuzhiyun #include <linux/platform_data/bcmgenet.h>
24*4882a593Smuzhiyun #include <linux/platform_data/mdio-bcm-unimac.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include "bcmgenet.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /* setup netdev link state when PHY link status change and
29*4882a593Smuzhiyun * update UMAC and RGMII block when link up
30*4882a593Smuzhiyun */
bcmgenet_mii_setup(struct net_device * dev)31*4882a593Smuzhiyun void bcmgenet_mii_setup(struct net_device *dev)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct bcmgenet_priv *priv = netdev_priv(dev);
34*4882a593Smuzhiyun struct phy_device *phydev = dev->phydev;
35*4882a593Smuzhiyun u32 reg, cmd_bits = 0;
36*4882a593Smuzhiyun bool status_changed = false;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (priv->old_link != phydev->link) {
39*4882a593Smuzhiyun status_changed = true;
40*4882a593Smuzhiyun priv->old_link = phydev->link;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun if (phydev->link) {
44*4882a593Smuzhiyun /* check speed/duplex/pause changes */
45*4882a593Smuzhiyun if (priv->old_speed != phydev->speed) {
46*4882a593Smuzhiyun status_changed = true;
47*4882a593Smuzhiyun priv->old_speed = phydev->speed;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (priv->old_duplex != phydev->duplex) {
51*4882a593Smuzhiyun status_changed = true;
52*4882a593Smuzhiyun priv->old_duplex = phydev->duplex;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun if (priv->old_pause != phydev->pause) {
56*4882a593Smuzhiyun status_changed = true;
57*4882a593Smuzhiyun priv->old_pause = phydev->pause;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* done if nothing has changed */
61*4882a593Smuzhiyun if (!status_changed)
62*4882a593Smuzhiyun return;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* speed */
65*4882a593Smuzhiyun if (phydev->speed == SPEED_1000)
66*4882a593Smuzhiyun cmd_bits = UMAC_SPEED_1000;
67*4882a593Smuzhiyun else if (phydev->speed == SPEED_100)
68*4882a593Smuzhiyun cmd_bits = UMAC_SPEED_100;
69*4882a593Smuzhiyun else
70*4882a593Smuzhiyun cmd_bits = UMAC_SPEED_10;
71*4882a593Smuzhiyun cmd_bits <<= CMD_SPEED_SHIFT;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* duplex */
74*4882a593Smuzhiyun if (phydev->duplex != DUPLEX_FULL)
75*4882a593Smuzhiyun cmd_bits |= CMD_HD_EN;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /* pause capability */
78*4882a593Smuzhiyun if (!phydev->pause)
79*4882a593Smuzhiyun cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /*
82*4882a593Smuzhiyun * Program UMAC and RGMII block based on established
83*4882a593Smuzhiyun * link speed, duplex, and pause. The speed set in
84*4882a593Smuzhiyun * umac->cmd tell RGMII block which clock to use for
85*4882a593Smuzhiyun * transmit -- 25MHz(100Mbps) or 125MHz(1Gbps).
86*4882a593Smuzhiyun * Receive clock is provided by the PHY.
87*4882a593Smuzhiyun */
88*4882a593Smuzhiyun reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
89*4882a593Smuzhiyun reg &= ~OOB_DISABLE;
90*4882a593Smuzhiyun reg |= RGMII_LINK;
91*4882a593Smuzhiyun bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun reg = bcmgenet_umac_readl(priv, UMAC_CMD);
94*4882a593Smuzhiyun reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
95*4882a593Smuzhiyun CMD_HD_EN |
96*4882a593Smuzhiyun CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
97*4882a593Smuzhiyun reg |= cmd_bits;
98*4882a593Smuzhiyun if (reg & CMD_SW_RESET) {
99*4882a593Smuzhiyun reg &= ~CMD_SW_RESET;
100*4882a593Smuzhiyun bcmgenet_umac_writel(priv, reg, UMAC_CMD);
101*4882a593Smuzhiyun udelay(2);
102*4882a593Smuzhiyun reg |= CMD_TX_EN | CMD_RX_EN;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun bcmgenet_umac_writel(priv, reg, UMAC_CMD);
105*4882a593Smuzhiyun } else {
106*4882a593Smuzhiyun /* done if nothing has changed */
107*4882a593Smuzhiyun if (!status_changed)
108*4882a593Smuzhiyun return;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /* needed for MoCA fixed PHY to reflect correct link status */
111*4882a593Smuzhiyun netif_carrier_off(dev);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun phy_print_status(phydev);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun
bcmgenet_fixed_phy_link_update(struct net_device * dev,struct fixed_phy_status * status)118*4882a593Smuzhiyun static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
119*4882a593Smuzhiyun struct fixed_phy_status *status)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun struct bcmgenet_priv *priv;
122*4882a593Smuzhiyun u32 reg;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (dev && dev->phydev && status) {
125*4882a593Smuzhiyun priv = netdev_priv(dev);
126*4882a593Smuzhiyun reg = bcmgenet_umac_readl(priv, UMAC_MODE);
127*4882a593Smuzhiyun status->link = !!(reg & MODE_LINK_STATUS);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
bcmgenet_phy_power_set(struct net_device * dev,bool enable)133*4882a593Smuzhiyun void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun struct bcmgenet_priv *priv = netdev_priv(dev);
136*4882a593Smuzhiyun u32 reg = 0;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */
139*4882a593Smuzhiyun if (GENET_IS_V4(priv)) {
140*4882a593Smuzhiyun reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
141*4882a593Smuzhiyun if (enable) {
142*4882a593Smuzhiyun reg &= ~EXT_CK25_DIS;
143*4882a593Smuzhiyun bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
144*4882a593Smuzhiyun mdelay(1);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
147*4882a593Smuzhiyun reg |= EXT_GPHY_RESET;
148*4882a593Smuzhiyun bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
149*4882a593Smuzhiyun mdelay(1);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun reg &= ~EXT_GPHY_RESET;
152*4882a593Smuzhiyun } else {
153*4882a593Smuzhiyun reg |= EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN |
154*4882a593Smuzhiyun EXT_GPHY_RESET;
155*4882a593Smuzhiyun bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
156*4882a593Smuzhiyun mdelay(1);
157*4882a593Smuzhiyun reg |= EXT_CK25_DIS;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
160*4882a593Smuzhiyun udelay(60);
161*4882a593Smuzhiyun } else {
162*4882a593Smuzhiyun mdelay(1);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
bcmgenet_moca_phy_setup(struct bcmgenet_priv * priv)166*4882a593Smuzhiyun static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun u32 reg;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (!GENET_IS_V5(priv)) {
171*4882a593Smuzhiyun /* Speed settings are set in bcmgenet_mii_setup() */
172*4882a593Smuzhiyun reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
173*4882a593Smuzhiyun reg |= LED_ACT_SOURCE_MAC;
174*4882a593Smuzhiyun bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET)
178*4882a593Smuzhiyun fixed_phy_set_link_update(priv->dev->phydev,
179*4882a593Smuzhiyun bcmgenet_fixed_phy_link_update);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
bcmgenet_mii_config(struct net_device * dev,bool init)182*4882a593Smuzhiyun int bcmgenet_mii_config(struct net_device *dev, bool init)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun struct bcmgenet_priv *priv = netdev_priv(dev);
185*4882a593Smuzhiyun struct phy_device *phydev = dev->phydev;
186*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
187*4882a593Smuzhiyun const char *phy_name = NULL;
188*4882a593Smuzhiyun u32 id_mode_dis = 0;
189*4882a593Smuzhiyun u32 port_ctrl;
190*4882a593Smuzhiyun u32 reg;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun switch (priv->phy_interface) {
193*4882a593Smuzhiyun case PHY_INTERFACE_MODE_INTERNAL:
194*4882a593Smuzhiyun phy_name = "internal PHY";
195*4882a593Smuzhiyun fallthrough;
196*4882a593Smuzhiyun case PHY_INTERFACE_MODE_MOCA:
197*4882a593Smuzhiyun /* Irrespective of the actually configured PHY speed (100 or
198*4882a593Smuzhiyun * 1000) GENETv4 only has an internal GPHY so we will just end
199*4882a593Smuzhiyun * up masking the Gigabit features from what we support, not
200*4882a593Smuzhiyun * switching to the EPHY
201*4882a593Smuzhiyun */
202*4882a593Smuzhiyun if (GENET_IS_V4(priv))
203*4882a593Smuzhiyun port_ctrl = PORT_MODE_INT_GPHY;
204*4882a593Smuzhiyun else
205*4882a593Smuzhiyun port_ctrl = PORT_MODE_INT_EPHY;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (!phy_name) {
208*4882a593Smuzhiyun phy_name = "MoCA";
209*4882a593Smuzhiyun bcmgenet_moca_phy_setup(priv);
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun case PHY_INTERFACE_MODE_MII:
214*4882a593Smuzhiyun phy_name = "external MII";
215*4882a593Smuzhiyun phy_set_max_speed(phydev, SPEED_100);
216*4882a593Smuzhiyun port_ctrl = PORT_MODE_EXT_EPHY;
217*4882a593Smuzhiyun break;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun case PHY_INTERFACE_MODE_REVMII:
220*4882a593Smuzhiyun phy_name = "external RvMII";
221*4882a593Smuzhiyun /* of_mdiobus_register took care of reading the 'max-speed'
222*4882a593Smuzhiyun * PHY property for us, effectively limiting the PHY supported
223*4882a593Smuzhiyun * capabilities, use that knowledge to also configure the
224*4882a593Smuzhiyun * Reverse MII interface correctly.
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
227*4882a593Smuzhiyun dev->phydev->supported))
228*4882a593Smuzhiyun port_ctrl = PORT_MODE_EXT_RVMII_50;
229*4882a593Smuzhiyun else
230*4882a593Smuzhiyun port_ctrl = PORT_MODE_EXT_RVMII_25;
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII:
234*4882a593Smuzhiyun /* RGMII_NO_ID: TXC transitions at the same time as TXD
235*4882a593Smuzhiyun * (requires PCB or receiver-side delay)
236*4882a593Smuzhiyun *
237*4882a593Smuzhiyun * ID is implicitly disabled for 100Mbps (RG)MII operation.
238*4882a593Smuzhiyun */
239*4882a593Smuzhiyun phy_name = "external RGMII (no delay)";
240*4882a593Smuzhiyun id_mode_dis = BIT(16);
241*4882a593Smuzhiyun port_ctrl = PORT_MODE_EXT_GPHY;
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_TXID:
245*4882a593Smuzhiyun /* RGMII_TXID: Add 2ns delay on TXC (90 degree shift) */
246*4882a593Smuzhiyun phy_name = "external RGMII (TX delay)";
247*4882a593Smuzhiyun port_ctrl = PORT_MODE_EXT_GPHY;
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun case PHY_INTERFACE_MODE_RGMII_RXID:
251*4882a593Smuzhiyun phy_name = "external RGMII (RX delay)";
252*4882a593Smuzhiyun port_ctrl = PORT_MODE_EXT_GPHY;
253*4882a593Smuzhiyun break;
254*4882a593Smuzhiyun default:
255*4882a593Smuzhiyun dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
256*4882a593Smuzhiyun return -EINVAL;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun priv->ext_phy = !priv->internal_phy &&
262*4882a593Smuzhiyun (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* This is an external PHY (xMII), so we need to enable the RGMII
265*4882a593Smuzhiyun * block for the interface to work
266*4882a593Smuzhiyun */
267*4882a593Smuzhiyun if (priv->ext_phy) {
268*4882a593Smuzhiyun reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
269*4882a593Smuzhiyun reg &= ~ID_MODE_DIS;
270*4882a593Smuzhiyun reg |= id_mode_dis;
271*4882a593Smuzhiyun if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
272*4882a593Smuzhiyun reg |= RGMII_MODE_EN_V123;
273*4882a593Smuzhiyun else
274*4882a593Smuzhiyun reg |= RGMII_MODE_EN;
275*4882a593Smuzhiyun bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (init)
279*4882a593Smuzhiyun dev_info(kdev, "configuring instance for %s\n", phy_name);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
bcmgenet_mii_probe(struct net_device * dev)284*4882a593Smuzhiyun int bcmgenet_mii_probe(struct net_device *dev)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun struct bcmgenet_priv *priv = netdev_priv(dev);
287*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
288*4882a593Smuzhiyun struct device_node *dn = kdev->of_node;
289*4882a593Smuzhiyun struct phy_device *phydev;
290*4882a593Smuzhiyun u32 phy_flags = 0;
291*4882a593Smuzhiyun int ret;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* Communicate the integrated PHY revision */
294*4882a593Smuzhiyun if (priv->internal_phy)
295*4882a593Smuzhiyun phy_flags = priv->gphy_rev;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun /* Initialize link state variables that bcmgenet_mii_setup() uses */
298*4882a593Smuzhiyun priv->old_link = -1;
299*4882a593Smuzhiyun priv->old_speed = -1;
300*4882a593Smuzhiyun priv->old_duplex = -1;
301*4882a593Smuzhiyun priv->old_pause = -1;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (dn) {
304*4882a593Smuzhiyun phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
305*4882a593Smuzhiyun phy_flags, priv->phy_interface);
306*4882a593Smuzhiyun if (!phydev) {
307*4882a593Smuzhiyun pr_err("could not attach to PHY\n");
308*4882a593Smuzhiyun return -ENODEV;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun } else {
311*4882a593Smuzhiyun if (has_acpi_companion(kdev)) {
312*4882a593Smuzhiyun char mdio_bus_id[MII_BUS_ID_SIZE];
313*4882a593Smuzhiyun struct mii_bus *unimacbus;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun snprintf(mdio_bus_id, MII_BUS_ID_SIZE, "%s-%d",
316*4882a593Smuzhiyun UNIMAC_MDIO_DRV_NAME, priv->pdev->id);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun unimacbus = mdio_find_bus(mdio_bus_id);
319*4882a593Smuzhiyun if (!unimacbus) {
320*4882a593Smuzhiyun pr_err("Unable to find mii\n");
321*4882a593Smuzhiyun return -ENODEV;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun phydev = phy_find_first(unimacbus);
324*4882a593Smuzhiyun put_device(&unimacbus->dev);
325*4882a593Smuzhiyun if (!phydev) {
326*4882a593Smuzhiyun pr_err("Unable to find PHY\n");
327*4882a593Smuzhiyun return -ENODEV;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun } else {
330*4882a593Smuzhiyun phydev = dev->phydev;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun phydev->dev_flags = phy_flags;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup,
335*4882a593Smuzhiyun priv->phy_interface);
336*4882a593Smuzhiyun if (ret) {
337*4882a593Smuzhiyun pr_err("could not attach to PHY\n");
338*4882a593Smuzhiyun return -ENODEV;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun /* Configure port multiplexer based on what the probed PHY device since
343*4882a593Smuzhiyun * reading the 'max-speed' property determines the maximum supported
344*4882a593Smuzhiyun * PHY speed which is needed for bcmgenet_mii_config() to configure
345*4882a593Smuzhiyun * things appropriately.
346*4882a593Smuzhiyun */
347*4882a593Smuzhiyun ret = bcmgenet_mii_config(dev, true);
348*4882a593Smuzhiyun if (ret) {
349*4882a593Smuzhiyun phy_disconnect(dev->phydev);
350*4882a593Smuzhiyun return ret;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun linkmode_copy(phydev->advertising, phydev->supported);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* The internal PHY has its link interrupts routed to the
356*4882a593Smuzhiyun * Ethernet MAC ISRs. On GENETv5 there is a hardware issue
357*4882a593Smuzhiyun * that prevents the signaling of link UP interrupts when
358*4882a593Smuzhiyun * the link operates at 10Mbps, so fallback to polling for
359*4882a593Smuzhiyun * those versions of GENET.
360*4882a593Smuzhiyun */
361*4882a593Smuzhiyun if (priv->internal_phy && !GENET_IS_V5(priv))
362*4882a593Smuzhiyun dev->phydev->irq = PHY_IGNORE_INTERRUPT;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
bcmgenet_mii_of_find_mdio(struct bcmgenet_priv * priv)367*4882a593Smuzhiyun static struct device_node *bcmgenet_mii_of_find_mdio(struct bcmgenet_priv *priv)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct device_node *dn = priv->pdev->dev.of_node;
370*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
371*4882a593Smuzhiyun char *compat;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
374*4882a593Smuzhiyun if (!compat)
375*4882a593Smuzhiyun return NULL;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun priv->mdio_dn = of_get_compatible_child(dn, compat);
378*4882a593Smuzhiyun kfree(compat);
379*4882a593Smuzhiyun if (!priv->mdio_dn) {
380*4882a593Smuzhiyun dev_err(kdev, "unable to find MDIO bus node\n");
381*4882a593Smuzhiyun return NULL;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return priv->mdio_dn;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
bcmgenet_mii_pdata_init(struct bcmgenet_priv * priv,struct unimac_mdio_pdata * ppd)387*4882a593Smuzhiyun static void bcmgenet_mii_pdata_init(struct bcmgenet_priv *priv,
388*4882a593Smuzhiyun struct unimac_mdio_pdata *ppd)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
391*4882a593Smuzhiyun struct bcmgenet_platform_data *pd = kdev->platform_data;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun if (pd->phy_interface != PHY_INTERFACE_MODE_MOCA && pd->mdio_enabled) {
394*4882a593Smuzhiyun /*
395*4882a593Smuzhiyun * Internal or external PHY with MDIO access
396*4882a593Smuzhiyun */
397*4882a593Smuzhiyun if (pd->phy_address >= 0 && pd->phy_address < PHY_MAX_ADDR)
398*4882a593Smuzhiyun ppd->phy_mask = 1 << pd->phy_address;
399*4882a593Smuzhiyun else
400*4882a593Smuzhiyun ppd->phy_mask = 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
bcmgenet_mii_wait(void * wait_func_data)404*4882a593Smuzhiyun static int bcmgenet_mii_wait(void *wait_func_data)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct bcmgenet_priv *priv = wait_func_data;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun wait_event_timeout(priv->wq,
409*4882a593Smuzhiyun !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
410*4882a593Smuzhiyun & MDIO_START_BUSY),
411*4882a593Smuzhiyun HZ / 100);
412*4882a593Smuzhiyun return 0;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
bcmgenet_mii_register(struct bcmgenet_priv * priv)415*4882a593Smuzhiyun static int bcmgenet_mii_register(struct bcmgenet_priv *priv)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun struct platform_device *pdev = priv->pdev;
418*4882a593Smuzhiyun struct bcmgenet_platform_data *pdata = pdev->dev.platform_data;
419*4882a593Smuzhiyun struct device_node *dn = pdev->dev.of_node;
420*4882a593Smuzhiyun struct unimac_mdio_pdata ppd;
421*4882a593Smuzhiyun struct platform_device *ppdev;
422*4882a593Smuzhiyun struct resource *pres, res;
423*4882a593Smuzhiyun int id, ret;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
426*4882a593Smuzhiyun if (!pres) {
427*4882a593Smuzhiyun dev_err(&pdev->dev, "Invalid resource\n");
428*4882a593Smuzhiyun return -EINVAL;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun memset(&res, 0, sizeof(res));
431*4882a593Smuzhiyun memset(&ppd, 0, sizeof(ppd));
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun ppd.wait_func = bcmgenet_mii_wait;
434*4882a593Smuzhiyun ppd.wait_func_data = priv;
435*4882a593Smuzhiyun ppd.bus_name = "bcmgenet MII bus";
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Unimac MDIO bus controller starts at UniMAC offset + MDIO_CMD
438*4882a593Smuzhiyun * and is 2 * 32-bits word long, 8 bytes total.
439*4882a593Smuzhiyun */
440*4882a593Smuzhiyun res.start = pres->start + GENET_UMAC_OFF + UMAC_MDIO_CMD;
441*4882a593Smuzhiyun res.end = res.start + 8;
442*4882a593Smuzhiyun res.flags = IORESOURCE_MEM;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (dn)
445*4882a593Smuzhiyun id = of_alias_get_id(dn, "eth");
446*4882a593Smuzhiyun else
447*4882a593Smuzhiyun id = pdev->id;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun ppdev = platform_device_alloc(UNIMAC_MDIO_DRV_NAME, id);
450*4882a593Smuzhiyun if (!ppdev)
451*4882a593Smuzhiyun return -ENOMEM;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /* Retain this platform_device pointer for later cleanup */
454*4882a593Smuzhiyun priv->mii_pdev = ppdev;
455*4882a593Smuzhiyun ppdev->dev.parent = &pdev->dev;
456*4882a593Smuzhiyun if (dn)
457*4882a593Smuzhiyun ppdev->dev.of_node = bcmgenet_mii_of_find_mdio(priv);
458*4882a593Smuzhiyun else if (pdata)
459*4882a593Smuzhiyun bcmgenet_mii_pdata_init(priv, &ppd);
460*4882a593Smuzhiyun else
461*4882a593Smuzhiyun ppd.phy_mask = ~0;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun ret = platform_device_add_resources(ppdev, &res, 1);
464*4882a593Smuzhiyun if (ret)
465*4882a593Smuzhiyun goto out;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd));
468*4882a593Smuzhiyun if (ret)
469*4882a593Smuzhiyun goto out;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun ret = platform_device_add(ppdev);
472*4882a593Smuzhiyun if (ret)
473*4882a593Smuzhiyun goto out;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun return 0;
476*4882a593Smuzhiyun out:
477*4882a593Smuzhiyun platform_device_put(ppdev);
478*4882a593Smuzhiyun return ret;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
bcmgenet_phy_interface_init(struct bcmgenet_priv * priv)481*4882a593Smuzhiyun static int bcmgenet_phy_interface_init(struct bcmgenet_priv *priv)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
484*4882a593Smuzhiyun int phy_mode = device_get_phy_mode(kdev);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun if (phy_mode < 0) {
487*4882a593Smuzhiyun dev_err(kdev, "invalid PHY mode property\n");
488*4882a593Smuzhiyun return phy_mode;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun priv->phy_interface = phy_mode;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun /* We need to specifically look up whether this PHY interface is
494*4882a593Smuzhiyun * internal or not *before* we even try to probe the PHY driver
495*4882a593Smuzhiyun * over MDIO as we may have shut down the internal PHY for power
496*4882a593Smuzhiyun * saving purposes.
497*4882a593Smuzhiyun */
498*4882a593Smuzhiyun if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
499*4882a593Smuzhiyun priv->internal_phy = true;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun return 0;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
bcmgenet_mii_of_init(struct bcmgenet_priv * priv)504*4882a593Smuzhiyun static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun struct device_node *dn = priv->pdev->dev.of_node;
507*4882a593Smuzhiyun struct phy_device *phydev;
508*4882a593Smuzhiyun int ret;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /* Fetch the PHY phandle */
511*4882a593Smuzhiyun priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /* In the case of a fixed PHY, the DT node associated
514*4882a593Smuzhiyun * to the PHY is the Ethernet MAC DT node.
515*4882a593Smuzhiyun */
516*4882a593Smuzhiyun if (!priv->phy_dn && of_phy_is_fixed_link(dn)) {
517*4882a593Smuzhiyun ret = of_phy_register_fixed_link(dn);
518*4882a593Smuzhiyun if (ret)
519*4882a593Smuzhiyun return ret;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun priv->phy_dn = of_node_get(dn);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* Get the link mode */
525*4882a593Smuzhiyun ret = bcmgenet_phy_interface_init(priv);
526*4882a593Smuzhiyun if (ret)
527*4882a593Smuzhiyun return ret;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* Make sure we initialize MoCA PHYs with a link down */
530*4882a593Smuzhiyun if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
531*4882a593Smuzhiyun phydev = of_phy_find_device(dn);
532*4882a593Smuzhiyun if (phydev) {
533*4882a593Smuzhiyun phydev->link = 0;
534*4882a593Smuzhiyun put_device(&phydev->mdio.dev);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return 0;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
bcmgenet_mii_pd_init(struct bcmgenet_priv * priv)541*4882a593Smuzhiyun static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
544*4882a593Smuzhiyun struct bcmgenet_platform_data *pd = kdev->platform_data;
545*4882a593Smuzhiyun char phy_name[MII_BUS_ID_SIZE + 3];
546*4882a593Smuzhiyun char mdio_bus_id[MII_BUS_ID_SIZE];
547*4882a593Smuzhiyun struct phy_device *phydev;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun snprintf(mdio_bus_id, MII_BUS_ID_SIZE, "%s-%d",
550*4882a593Smuzhiyun UNIMAC_MDIO_DRV_NAME, priv->pdev->id);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun if (pd->phy_interface != PHY_INTERFACE_MODE_MOCA && pd->mdio_enabled) {
553*4882a593Smuzhiyun snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT,
554*4882a593Smuzhiyun mdio_bus_id, pd->phy_address);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /*
557*4882a593Smuzhiyun * Internal or external PHY with MDIO access
558*4882a593Smuzhiyun */
559*4882a593Smuzhiyun phydev = phy_attach(priv->dev, phy_name, pd->phy_interface);
560*4882a593Smuzhiyun if (!phydev) {
561*4882a593Smuzhiyun dev_err(kdev, "failed to register PHY device\n");
562*4882a593Smuzhiyun return -ENODEV;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun } else {
565*4882a593Smuzhiyun /*
566*4882a593Smuzhiyun * MoCA port or no MDIO access.
567*4882a593Smuzhiyun * Use fixed PHY to represent the link layer.
568*4882a593Smuzhiyun */
569*4882a593Smuzhiyun struct fixed_phy_status fphy_status = {
570*4882a593Smuzhiyun .link = 1,
571*4882a593Smuzhiyun .speed = pd->phy_speed,
572*4882a593Smuzhiyun .duplex = pd->phy_duplex,
573*4882a593Smuzhiyun .pause = 0,
574*4882a593Smuzhiyun .asym_pause = 0,
575*4882a593Smuzhiyun };
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
578*4882a593Smuzhiyun if (!phydev || IS_ERR(phydev)) {
579*4882a593Smuzhiyun dev_err(kdev, "failed to register fixed PHY device\n");
580*4882a593Smuzhiyun return -ENODEV;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun /* Make sure we initialize MoCA PHYs with a link down */
584*4882a593Smuzhiyun phydev->link = 0;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun priv->phy_interface = pd->phy_interface;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
bcmgenet_mii_bus_init(struct bcmgenet_priv * priv)593*4882a593Smuzhiyun static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun struct device *kdev = &priv->pdev->dev;
596*4882a593Smuzhiyun struct device_node *dn = kdev->of_node;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun if (dn)
599*4882a593Smuzhiyun return bcmgenet_mii_of_init(priv);
600*4882a593Smuzhiyun else if (has_acpi_companion(kdev))
601*4882a593Smuzhiyun return bcmgenet_phy_interface_init(priv);
602*4882a593Smuzhiyun else
603*4882a593Smuzhiyun return bcmgenet_mii_pd_init(priv);
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
bcmgenet_mii_init(struct net_device * dev)606*4882a593Smuzhiyun int bcmgenet_mii_init(struct net_device *dev)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun struct bcmgenet_priv *priv = netdev_priv(dev);
609*4882a593Smuzhiyun int ret;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun ret = bcmgenet_mii_register(priv);
612*4882a593Smuzhiyun if (ret)
613*4882a593Smuzhiyun return ret;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun ret = bcmgenet_mii_bus_init(priv);
616*4882a593Smuzhiyun if (ret)
617*4882a593Smuzhiyun goto out;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun return 0;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun out:
622*4882a593Smuzhiyun bcmgenet_mii_exit(dev);
623*4882a593Smuzhiyun return ret;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
bcmgenet_mii_exit(struct net_device * dev)626*4882a593Smuzhiyun void bcmgenet_mii_exit(struct net_device *dev)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun struct bcmgenet_priv *priv = netdev_priv(dev);
629*4882a593Smuzhiyun struct device_node *dn = priv->pdev->dev.of_node;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun if (of_phy_is_fixed_link(dn))
632*4882a593Smuzhiyun of_phy_deregister_fixed_link(dn);
633*4882a593Smuzhiyun of_node_put(priv->phy_dn);
634*4882a593Smuzhiyun platform_device_unregister(priv->mii_pdev);
635*4882a593Smuzhiyun }
636