Merge tag 'tags/upstream-4.20-rc1' of git://git.infradead.org/linux-ubifs
[sfrench/cifs-2.6.git] / drivers / staging / mt7621-eth / mdio.c
1 /*   This program is free software; you can redistribute it and/or modify
2  *   it under the terms of the GNU General Public License as published by
3  *   the Free Software Foundation; version 2 of the License
4  *
5  *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
6  *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
7  *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
8  */
9
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/phy.h>
13 #include <linux/of_net.h>
14 #include <linux/of_mdio.h>
15
16 #include "mtk_eth_soc.h"
17 #include "mdio.h"
18
19 static int mtk_mdio_reset(struct mii_bus *bus)
20 {
21         /* TODO */
22         return 0;
23 }
24
25 static void mtk_phy_link_adjust(struct net_device *dev)
26 {
27         struct mtk_eth *eth = netdev_priv(dev);
28         unsigned long flags;
29         int i;
30
31         spin_lock_irqsave(&eth->phy->lock, flags);
32         for (i = 0; i < 8; i++) {
33                 if (eth->phy->phy_node[i]) {
34                         struct phy_device *phydev = eth->phy->phy[i];
35                         int status_change = 0;
36
37                         if (phydev->link)
38                                 if (eth->phy->duplex[i] != phydev->duplex ||
39                                     eth->phy->speed[i] != phydev->speed)
40                                         status_change = 1;
41
42                         if (phydev->link != eth->link[i])
43                                 status_change = 1;
44
45                         switch (phydev->speed) {
46                         case SPEED_1000:
47                         case SPEED_100:
48                         case SPEED_10:
49                                 eth->link[i] = phydev->link;
50                                 eth->phy->duplex[i] = phydev->duplex;
51                                 eth->phy->speed[i] = phydev->speed;
52
53                                 if (status_change &&
54                                     eth->soc->mdio_adjust_link)
55                                         eth->soc->mdio_adjust_link(eth, i);
56                                 break;
57                         }
58                 }
59         }
60         spin_unlock_irqrestore(&eth->phy->lock, flags);
61 }
62
63 int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac,
64                          struct device_node *phy_node)
65 {
66         const __be32 *_port = NULL;
67         struct phy_device *phydev;
68         int phy_mode, port;
69
70         _port = of_get_property(phy_node, "reg", NULL);
71
72         if (!_port || (be32_to_cpu(*_port) >= 0x20)) {
73                 pr_err("%pOFn: invalid port id\n", phy_node);
74                 return -EINVAL;
75         }
76         port = be32_to_cpu(*_port);
77         phy_mode = of_get_phy_mode(phy_node);
78         if (phy_mode < 0) {
79                 dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode);
80                 eth->phy->phy_node[port] = NULL;
81                 return -EINVAL;
82         }
83
84         phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
85                                 mtk_phy_link_adjust, 0, phy_mode);
86         if (!phydev) {
87                 dev_err(eth->dev, "could not connect to PHY\n");
88                 eth->phy->phy_node[port] = NULL;
89                 return -ENODEV;
90         }
91
92         phydev->supported &= PHY_GBIT_FEATURES;
93         phydev->advertising = phydev->supported;
94
95         dev_info(eth->dev,
96                  "connected port %d to PHY at %s [uid=%08x, driver=%s]\n",
97                  port, phydev_name(phydev), phydev->phy_id,
98                  phydev->drv->name);
99
100         eth->phy->phy[port] = phydev;
101         eth->link[port] = 0;
102
103         return 0;
104 }
105
106 static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac,
107                      struct phy_device *phy)
108 {
109         phy_attach(eth->netdev[mac->id], phydev_name(phy),
110                    PHY_INTERFACE_MODE_MII);
111
112         phy->autoneg = AUTONEG_ENABLE;
113         phy->speed = 0;
114         phy->duplex = 0;
115         phy_set_max_speed(phy, SPEED_100);
116         phy->advertising = phy->supported | ADVERTISED_Autoneg;
117
118         phy_start_aneg(phy);
119 }
120
121 static int mtk_phy_connect(struct mtk_mac *mac)
122 {
123         struct mtk_eth *eth = mac->hw;
124         int i;
125
126         for (i = 0; i < 8; i++) {
127                 if (eth->phy->phy_node[i]) {
128                         if (!mac->phy_dev) {
129                                 mac->phy_dev = eth->phy->phy[i];
130                                 mac->phy_flags = MTK_PHY_FLAG_PORT;
131                         }
132                 } else if (eth->mii_bus) {
133                         struct phy_device *phy;
134
135                         phy = mdiobus_get_phy(eth->mii_bus, i);
136                         if (phy) {
137                                 phy_init(eth, mac, phy);
138                                 if (!mac->phy_dev) {
139                                         mac->phy_dev = phy;
140                                         mac->phy_flags = MTK_PHY_FLAG_ATTACH;
141                                 }
142                         }
143                 }
144         }
145
146         return 0;
147 }
148
149 static void mtk_phy_disconnect(struct mtk_mac *mac)
150 {
151         struct mtk_eth *eth = mac->hw;
152         unsigned long flags;
153         int i;
154
155         for (i = 0; i < 8; i++)
156                 if (eth->phy->phy_fixed[i]) {
157                         spin_lock_irqsave(&eth->phy->lock, flags);
158                         eth->link[i] = 0;
159                         if (eth->soc->mdio_adjust_link)
160                                 eth->soc->mdio_adjust_link(eth, i);
161                         spin_unlock_irqrestore(&eth->phy->lock, flags);
162                 } else if (eth->phy->phy[i]) {
163                         phy_disconnect(eth->phy->phy[i]);
164                 } else if (eth->mii_bus) {
165                         struct phy_device *phy =
166                                 mdiobus_get_phy(eth->mii_bus, i);
167
168                         if (phy)
169                                 phy_detach(phy);
170                 }
171 }
172
173 static void mtk_phy_start(struct mtk_mac *mac)
174 {
175         struct mtk_eth *eth = mac->hw;
176         unsigned long flags;
177         int i;
178
179         for (i = 0; i < 8; i++) {
180                 if (eth->phy->phy_fixed[i]) {
181                         spin_lock_irqsave(&eth->phy->lock, flags);
182                         eth->link[i] = 1;
183                         if (eth->soc->mdio_adjust_link)
184                                 eth->soc->mdio_adjust_link(eth, i);
185                         spin_unlock_irqrestore(&eth->phy->lock, flags);
186                 } else if (eth->phy->phy[i]) {
187                         phy_start(eth->phy->phy[i]);
188                 }
189         }
190 }
191
192 static void mtk_phy_stop(struct mtk_mac *mac)
193 {
194         struct mtk_eth *eth = mac->hw;
195         unsigned long flags;
196         int i;
197
198         for (i = 0; i < 8; i++)
199                 if (eth->phy->phy_fixed[i]) {
200                         spin_lock_irqsave(&eth->phy->lock, flags);
201                         eth->link[i] = 0;
202                         if (eth->soc->mdio_adjust_link)
203                                 eth->soc->mdio_adjust_link(eth, i);
204                         spin_unlock_irqrestore(&eth->phy->lock, flags);
205                 } else if (eth->phy->phy[i]) {
206                         phy_stop(eth->phy->phy[i]);
207                 }
208 }
209
210 static struct mtk_phy phy_ralink = {
211         .connect = mtk_phy_connect,
212         .disconnect = mtk_phy_disconnect,
213         .start = mtk_phy_start,
214         .stop = mtk_phy_stop,
215 };
216
217 int mtk_mdio_init(struct mtk_eth *eth)
218 {
219         struct device_node *mii_np;
220         int err;
221
222         if (!eth->soc->mdio_read || !eth->soc->mdio_write)
223                 return 0;
224
225         spin_lock_init(&phy_ralink.lock);
226         eth->phy = &phy_ralink;
227
228         mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
229         if (!mii_np) {
230                 dev_err(eth->dev, "no %s child node found", "mdio-bus");
231                 return -ENODEV;
232         }
233
234         if (!of_device_is_available(mii_np)) {
235                 err = 0;
236                 goto err_put_node;
237         }
238
239         eth->mii_bus = mdiobus_alloc();
240         if (!eth->mii_bus) {
241                 err = -ENOMEM;
242                 goto err_put_node;
243         }
244
245         eth->mii_bus->name = "mdio";
246         eth->mii_bus->read = eth->soc->mdio_read;
247         eth->mii_bus->write = eth->soc->mdio_write;
248         eth->mii_bus->reset = mtk_mdio_reset;
249         eth->mii_bus->priv = eth;
250         eth->mii_bus->parent = eth->dev;
251
252         snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
253         err = of_mdiobus_register(eth->mii_bus, mii_np);
254         if (err)
255                 goto err_free_bus;
256
257         return 0;
258
259 err_free_bus:
260         kfree(eth->mii_bus);
261 err_put_node:
262         of_node_put(mii_np);
263         eth->mii_bus = NULL;
264         return err;
265 }
266
267 void mtk_mdio_cleanup(struct mtk_eth *eth)
268 {
269         if (!eth->mii_bus)
270                 return;
271
272         mdiobus_unregister(eth->mii_bus);
273         of_node_put(eth->mii_bus->dev.of_node);
274         kfree(eth->mii_bus);
275 }