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
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>
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>
16 #include "mtk_eth_soc.h"
19 static int mtk_mdio_reset(struct mii_bus
*bus
)
25 static void mtk_phy_link_adjust(struct net_device
*dev
)
27 struct mtk_eth
*eth
= netdev_priv(dev
);
31 spin_lock_irqsave(ð
->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;
38 if (eth
->phy
->duplex
[i
] != phydev
->duplex
||
39 eth
->phy
->speed
[i
] != phydev
->speed
)
42 if (phydev
->link
!= eth
->link
[i
])
45 switch (phydev
->speed
) {
49 eth
->link
[i
] = phydev
->link
;
50 eth
->phy
->duplex
[i
] = phydev
->duplex
;
51 eth
->phy
->speed
[i
] = phydev
->speed
;
54 eth
->soc
->mdio_adjust_link
)
55 eth
->soc
->mdio_adjust_link(eth
, i
);
60 spin_unlock_irqrestore(ð
->phy
->lock
, flags
);
63 int mtk_connect_phy_node(struct mtk_eth
*eth
, struct mtk_mac
*mac
,
64 struct device_node
*phy_node
)
66 const __be32
*_port
= NULL
;
67 struct phy_device
*phydev
;
70 _port
= of_get_property(phy_node
, "reg", NULL
);
72 if (!_port
|| (be32_to_cpu(*_port
) >= 0x20)) {
73 pr_err("%s: invalid port id\n", phy_node
->name
);
76 port
= be32_to_cpu(*_port
);
77 phy_mode
= of_get_phy_mode(phy_node
);
79 dev_err(eth
->dev
, "incorrect phy-mode %d\n", phy_mode
);
80 eth
->phy
->phy_node
[port
] = NULL
;
84 phydev
= of_phy_connect(eth
->netdev
[mac
->id
], phy_node
,
85 mtk_phy_link_adjust
, 0, phy_mode
);
87 dev_err(eth
->dev
, "could not connect to PHY\n");
88 eth
->phy
->phy_node
[port
] = NULL
;
92 phydev
->supported
&= PHY_GBIT_FEATURES
;
93 phydev
->advertising
= phydev
->supported
;
96 "connected port %d to PHY at %s [uid=%08x, driver=%s]\n",
97 port
, phydev_name(phydev
), phydev
->phy_id
,
100 eth
->phy
->phy
[port
] = phydev
;
106 static void phy_init(struct mtk_eth
*eth
, struct mtk_mac
*mac
,
107 struct phy_device
*phy
)
109 phy_attach(eth
->netdev
[mac
->id
], phydev_name(phy
),
110 PHY_INTERFACE_MODE_MII
);
112 phy
->autoneg
= AUTONEG_ENABLE
;
115 phy
->supported
&= PHY_BASIC_FEATURES
;
116 phy
->advertising
= phy
->supported
| ADVERTISED_Autoneg
;
121 static int mtk_phy_connect(struct mtk_mac
*mac
)
123 struct mtk_eth
*eth
= mac
->hw
;
126 for (i
= 0; i
< 8; i
++) {
127 if (eth
->phy
->phy_node
[i
]) {
129 mac
->phy_dev
= eth
->phy
->phy
[i
];
130 mac
->phy_flags
= MTK_PHY_FLAG_PORT
;
132 } else if (eth
->mii_bus
) {
133 struct phy_device
*phy
;
135 phy
= mdiobus_get_phy(eth
->mii_bus
, i
);
137 phy_init(eth
, mac
, phy
);
140 mac
->phy_flags
= MTK_PHY_FLAG_ATTACH
;
149 static void mtk_phy_disconnect(struct mtk_mac
*mac
)
151 struct mtk_eth
*eth
= mac
->hw
;
155 for (i
= 0; i
< 8; i
++)
156 if (eth
->phy
->phy_fixed
[i
]) {
157 spin_lock_irqsave(ð
->phy
->lock
, flags
);
159 if (eth
->soc
->mdio_adjust_link
)
160 eth
->soc
->mdio_adjust_link(eth
, i
);
161 spin_unlock_irqrestore(ð
->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
);
173 static void mtk_phy_start(struct mtk_mac
*mac
)
175 struct mtk_eth
*eth
= mac
->hw
;
179 for (i
= 0; i
< 8; i
++) {
180 if (eth
->phy
->phy_fixed
[i
]) {
181 spin_lock_irqsave(ð
->phy
->lock
, flags
);
183 if (eth
->soc
->mdio_adjust_link
)
184 eth
->soc
->mdio_adjust_link(eth
, i
);
185 spin_unlock_irqrestore(ð
->phy
->lock
, flags
);
186 } else if (eth
->phy
->phy
[i
]) {
187 phy_start(eth
->phy
->phy
[i
]);
192 static void mtk_phy_stop(struct mtk_mac
*mac
)
194 struct mtk_eth
*eth
= mac
->hw
;
198 for (i
= 0; i
< 8; i
++)
199 if (eth
->phy
->phy_fixed
[i
]) {
200 spin_lock_irqsave(ð
->phy
->lock
, flags
);
202 if (eth
->soc
->mdio_adjust_link
)
203 eth
->soc
->mdio_adjust_link(eth
, i
);
204 spin_unlock_irqrestore(ð
->phy
->lock
, flags
);
205 } else if (eth
->phy
->phy
[i
]) {
206 phy_stop(eth
->phy
->phy
[i
]);
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
,
217 int mtk_mdio_init(struct mtk_eth
*eth
)
219 struct device_node
*mii_np
;
222 if (!eth
->soc
->mdio_read
|| !eth
->soc
->mdio_write
)
225 spin_lock_init(&phy_ralink
.lock
);
226 eth
->phy
= &phy_ralink
;
228 mii_np
= of_get_child_by_name(eth
->dev
->of_node
, "mdio-bus");
230 dev_err(eth
->dev
, "no %s child node found", "mdio-bus");
234 if (!of_device_is_available(mii_np
)) {
239 eth
->mii_bus
= mdiobus_alloc();
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
;
252 snprintf(eth
->mii_bus
->id
, MII_BUS_ID_SIZE
, "%s", mii_np
->name
);
253 err
= of_mdiobus_register(eth
->mii_bus
, mii_np
);
267 void mtk_mdio_cleanup(struct mtk_eth
*eth
)
272 mdiobus_unregister(eth
->mii_bus
);
273 of_node_put(eth
->mii_bus
->dev
.of_node
);