net: mscc: ocelot: make use of SerDes PHYs for handling their configuration

Previously, the SerDes muxing was hardcoded to a given mode in the MAC
controller driver. Now, the SerDes muxing is configured within the
Device Tree and is enforced in the MAC controller driver so we can have
a lot of different SerDes configurations.

Make use of the SerDes PHYs in the MAC controller to set up the SerDes
according to the SerDes<->switch port mapping and the communication mode
with the Ethernet PHY.

Signed-off-by: Quentin Schulz <quentin.schulz@bootlin.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Quentin Schulz
2018-10-04 14:22:08 +02:00
committed by David S. Miller
parent 51f6b410fc
commit 71e32a20cf
5 changed files with 63 additions and 12 deletions

View File

@@ -6,6 +6,7 @@
*/
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_net.h>
#include <linux/netdevice.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
@@ -253,18 +254,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ocelot->multicast);
ocelot_init(ocelot);
ocelot_rmw(ocelot, HSIO_HW_CFG_DEV1G_4_MODE |
HSIO_HW_CFG_DEV1G_6_MODE |
HSIO_HW_CFG_DEV1G_9_MODE,
HSIO_HW_CFG_DEV1G_4_MODE |
HSIO_HW_CFG_DEV1G_6_MODE |
HSIO_HW_CFG_DEV1G_9_MODE,
HSIO_HW_CFG);
for_each_available_child_of_node(ports, portnp) {
struct device_node *phy_node;
struct phy_device *phy;
struct resource *res;
struct phy *serdes;
enum phy_mode phy_mode;
void __iomem *regs;
char res_name[8];
u32 port;
@@ -289,10 +284,45 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
continue;
err = ocelot_probe_port(ocelot, port, regs, phy);
if (err) {
dev_err(&pdev->dev, "failed to probe ports\n");
if (err)
return err;
err = of_get_phy_mode(portnp);
if (err < 0)
ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA;
else
ocelot->ports[port]->phy_mode = err;
switch (ocelot->ports[port]->phy_mode) {
case PHY_INTERFACE_MODE_NA:
continue;
case PHY_INTERFACE_MODE_SGMII:
phy_mode = PHY_MODE_SGMII;
break;
case PHY_INTERFACE_MODE_QSGMII:
phy_mode = PHY_MODE_QSGMII;
break;
default:
dev_err(ocelot->dev,
"invalid phy mode for port%d, (Q)SGMII only\n",
port);
return -EINVAL;
}
serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
if (IS_ERR(serdes)) {
err = PTR_ERR(serdes);
if (err == -EPROBE_DEFER)
dev_dbg(ocelot->dev, "deferring probe\n");
else
dev_err(ocelot->dev,
"missing SerDes phys for port%d\n",
port);
goto err_probe_ports;
}
ocelot->ports[port]->serdes = serdes;
}
register_netdevice_notifier(&ocelot_netdevice_nb);