net: axienet: Fix double deregister of mdio
[linux-2.6-microblaze.git] / drivers / net / ethernet / xilinx / xilinx_axienet_mdio.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MDIO bus driver for the Xilinx Axi Ethernet device
4  *
5  * Copyright (c) 2009 Secret Lab Technologies, Ltd.
6  * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu>
7  * Copyright (c) 2010 - 2011 PetaLogix
8  * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved.
9  */
10
11 #include <linux/of_address.h>
12 #include <linux/of_mdio.h>
13 #include <linux/jiffies.h>
14
15 #include "xilinx_axienet.h"
16
17 #define MAX_MDIO_FREQ           2500000 /* 2.5 MHz */
18 #define DEFAULT_CLOCK_DIVISOR   XAE_MDIO_DIV_DFT
19
20 /* Wait till MDIO interface is ready to accept a new transaction.*/
21 int axienet_mdio_wait_until_ready(struct axienet_local *lp)
22 {
23         unsigned long end = jiffies + 2;
24         while (!(axienet_ior(lp, XAE_MDIO_MCR_OFFSET) &
25                  XAE_MDIO_MCR_READY_MASK)) {
26                 if (time_before_eq(end, jiffies)) {
27                         WARN_ON(1);
28                         return -ETIMEDOUT;
29                 }
30                 udelay(1);
31         }
32         return 0;
33 }
34
35 /**
36  * axienet_mdio_read - MDIO interface read function
37  * @bus:        Pointer to mii bus structure
38  * @phy_id:     Address of the PHY device
39  * @reg:        PHY register to read
40  *
41  * Return:      The register contents on success, -ETIMEDOUT on a timeout
42  *
43  * Reads the contents of the requested register from the requested PHY
44  * address by first writing the details into MCR register. After a while
45  * the register MRD is read to obtain the PHY register content.
46  */
47 static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg)
48 {
49         u32 rc;
50         int ret;
51         struct axienet_local *lp = bus->priv;
52
53         ret = axienet_mdio_wait_until_ready(lp);
54         if (ret < 0)
55                 return ret;
56
57         axienet_iow(lp, XAE_MDIO_MCR_OFFSET,
58                     (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) &
59                       XAE_MDIO_MCR_PHYAD_MASK) |
60                      ((reg << XAE_MDIO_MCR_REGAD_SHIFT) &
61                       XAE_MDIO_MCR_REGAD_MASK) |
62                      XAE_MDIO_MCR_INITIATE_MASK |
63                      XAE_MDIO_MCR_OP_READ_MASK));
64
65         ret = axienet_mdio_wait_until_ready(lp);
66         if (ret < 0)
67                 return ret;
68
69         rc = axienet_ior(lp, XAE_MDIO_MRD_OFFSET) & 0x0000FFFF;
70
71         dev_dbg(lp->dev, "axienet_mdio_read(phy_id=%i, reg=%x) == %x\n",
72                 phy_id, reg, rc);
73
74         return rc;
75 }
76
77 /**
78  * axienet_mdio_write - MDIO interface write function
79  * @bus:        Pointer to mii bus structure
80  * @phy_id:     Address of the PHY device
81  * @reg:        PHY register to write to
82  * @val:        Value to be written into the register
83  *
84  * Return:      0 on success, -ETIMEDOUT on a timeout
85  *
86  * Writes the value to the requested register by first writing the value
87  * into MWD register. The the MCR register is then appropriately setup
88  * to finish the write operation.
89  */
90 static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
91                               u16 val)
92 {
93         int ret;
94         struct axienet_local *lp = bus->priv;
95
96         dev_dbg(lp->dev, "axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
97                 phy_id, reg, val);
98
99         ret = axienet_mdio_wait_until_ready(lp);
100         if (ret < 0)
101                 return ret;
102
103         axienet_iow(lp, XAE_MDIO_MWD_OFFSET, (u32) val);
104         axienet_iow(lp, XAE_MDIO_MCR_OFFSET,
105                     (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) &
106                       XAE_MDIO_MCR_PHYAD_MASK) |
107                      ((reg << XAE_MDIO_MCR_REGAD_SHIFT) &
108                       XAE_MDIO_MCR_REGAD_MASK) |
109                      XAE_MDIO_MCR_INITIATE_MASK |
110                      XAE_MDIO_MCR_OP_WRITE_MASK));
111
112         ret = axienet_mdio_wait_until_ready(lp);
113         if (ret < 0)
114                 return ret;
115         return 0;
116 }
117
118 /**
119  * axienet_mdio_setup - MDIO setup function
120  * @lp:         Pointer to axienet local data structure.
121  * @np:         Pointer to device node
122  *
123  * Return:      0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
124  *              mdiobus_alloc (to allocate memory for mii bus structure) fails.
125  *
126  * Sets up the MDIO interface by initializing the MDIO clock and enabling the
127  * MDIO interface in hardware. Register the MDIO interface.
128  **/
129 int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
130 {
131         int ret;
132         u32 clk_div, host_clock;
133         struct mii_bus *bus;
134         struct resource res;
135         struct device_node *np1;
136
137         /* clk_div can be calculated by deriving it from the equation:
138          * fMDIO = fHOST / ((1 + clk_div) * 2)
139          *
140          * Where fMDIO <= 2500000, so we get:
141          * fHOST / ((1 + clk_div) * 2) <= 2500000
142          *
143          * Then we get:
144          * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST)
145          *
146          * Then we get:
147          * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST)
148          *
149          * Then we get:
150          * 1 / (1 + clk_div) <= (5000000 / fHOST)
151          *
152          * So:
153          * (1 + clk_div) >= (fHOST / 5000000)
154          *
155          * And finally:
156          * clk_div >= (fHOST / 5000000) - 1
157          *
158          * fHOST can be read from the flattened device tree as property
159          * "clock-frequency" from the CPU
160          */
161
162         np1 = of_find_node_by_name(NULL, "cpu");
163         if (!np1) {
164                 netdev_warn(lp->ndev, "Could not find CPU device node.\n");
165                 netdev_warn(lp->ndev,
166                             "Setting MDIO clock divisor to default %d\n",
167                             DEFAULT_CLOCK_DIVISOR);
168                 clk_div = DEFAULT_CLOCK_DIVISOR;
169                 goto issue;
170         }
171         if (of_property_read_u32(np1, "clock-frequency", &host_clock)) {
172                 netdev_warn(lp->ndev, "clock-frequency property not found.\n");
173                 netdev_warn(lp->ndev,
174                             "Setting MDIO clock divisor to default %d\n",
175                             DEFAULT_CLOCK_DIVISOR);
176                 clk_div = DEFAULT_CLOCK_DIVISOR;
177                 of_node_put(np1);
178                 goto issue;
179         }
180
181         clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
182         /* If there is any remainder from the division of
183          * fHOST / (MAX_MDIO_FREQ * 2), then we need to add
184          * 1 to the clock divisor or we will surely be above 2.5 MHz
185          */
186         if (host_clock % (MAX_MDIO_FREQ * 2))
187                 clk_div++;
188
189         netdev_dbg(lp->ndev,
190                    "Setting MDIO clock divisor to %u/%u Hz host clock.\n",
191                    clk_div, host_clock);
192
193         of_node_put(np1);
194 issue:
195         axienet_iow(lp, XAE_MDIO_MC_OFFSET,
196                     (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK));
197
198         ret = axienet_mdio_wait_until_ready(lp);
199         if (ret < 0)
200                 return ret;
201
202         bus = mdiobus_alloc();
203         if (!bus)
204                 return -ENOMEM;
205
206         np1 = of_get_parent(lp->phy_node);
207         of_address_to_resource(np1, 0, &res);
208         snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
209                  (unsigned long long) res.start);
210
211         bus->priv = lp;
212         bus->name = "Xilinx Axi Ethernet MDIO";
213         bus->read = axienet_mdio_read;
214         bus->write = axienet_mdio_write;
215         bus->parent = lp->dev;
216         lp->mii_bus = bus;
217
218         ret = of_mdiobus_register(bus, np1);
219         if (ret) {
220                 mdiobus_free(bus);
221                 lp->mii_bus = NULL;
222                 return ret;
223         }
224         return 0;
225 }
226
227 /**
228  * axienet_mdio_teardown - MDIO remove function
229  * @lp:         Pointer to axienet local data structure.
230  *
231  * Unregisters the MDIO and frees any associate memory for mii bus.
232  */
233 void axienet_mdio_teardown(struct axienet_local *lp)
234 {
235         mdiobus_unregister(lp->mii_bus);
236         mdiobus_free(lp->mii_bus);
237         lp->mii_bus = NULL;
238 }