aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch')
-rw-r--r--target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch332
1 files changed, 0 insertions, 332 deletions
diff --git a/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch b/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch
deleted file mode 100644
index 82fd96515d..0000000000
--- a/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch
+++ /dev/null
@@ -1,332 +0,0 @@
-From 86f4ea63e696db996f68d1065b55506e75a7d765 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Fri, 20 Dec 2013 02:16:10 +0100
-Subject: [PATCH 205/208] b44: add phylib support
-
-Most of the older home routers based on the Broadcom BCM47XX SoC series
-are using a MAC that is supported by b44. On most of these routers not
-the internal PHY of this MAC core is used, but a switch sometimes on an
-external chip or integrated into the same SoC as the Ethernet core.
-For this switch a special PHY driver is needed which should not be
-integrated into b44 as the same switches are also used by other
-Broadcom home networking SoCs which are using different Ethernet MAC
-drivers. This was tested with the b53 switch driver which is currently
-on its way to mainline.
-
-If the internal PHY is not used, b44 will now search on the MDIO bus
-for a phy and use the Linux phylib subsystem to register a driver.
-Support for the internal PHY must stay here, because there are some
-device which are suing the internal phy.
-
-With this patch we scan the mdio bus when the sprom or nvram says that
-the PHY address is 30, if a PHY was found at this address b44 uses it.
-
-This was tested with a BCM4704, BCM4712 and BCM5354.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/ethernet/broadcom/Kconfig | 1 +
- drivers/net/ethernet/broadcom/b44.c | 190 ++++++++++++++++++++++++++++++++-
- drivers/net/ethernet/broadcom/b44.h | 3 +
- 3 files changed, 189 insertions(+), 5 deletions(-)
-
---- a/drivers/net/ethernet/broadcom/Kconfig
-+++ b/drivers/net/ethernet/broadcom/Kconfig
-@@ -24,6 +24,7 @@ config B44
- select SSB
- select NET_CORE
- select MII
-+ select PHYLIB
- ---help---
- If you have a network (Ethernet) controller of this type, say Y
- or M and read the Ethernet-HOWTO, available from
---- a/drivers/net/ethernet/broadcom/b44.c
-+++ b/drivers/net/ethernet/broadcom/b44.c
-@@ -6,6 +6,7 @@
- * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
- * Copyright (C) 2006 Broadcom Corporation.
- * Copyright (C) 2007 Michael Buesch <m@bues.ch>
-+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * Distribute under GPL.
- */
-@@ -29,6 +30,7 @@
- #include <linux/dma-mapping.h>
- #include <linux/ssb/ssb.h>
- #include <linux/slab.h>
-+#include <linux/phy.h>
-
- #include <asm/uaccess.h>
- #include <asm/io.h>
-@@ -316,6 +318,23 @@ static void b44_mdio_write_mii(struct ne
- __b44_writephy(bp, phy_id, location, val);
- }
-
-+static int b44_mdio_read_phylib(struct mii_bus *bus, int phy_id, int location)
-+{
-+ u32 val;
-+ struct b44 *bp = bus->priv;
-+ int rc = __b44_readphy(bp, phy_id, location, &val);
-+ if (rc)
-+ return 0xffffffff;
-+ return val;
-+}
-+
-+static int b44_mdio_write_phylib(struct mii_bus *bus, int phy_id, int location,
-+ u16 val)
-+{
-+ struct b44 *bp = bus->priv;
-+ return __b44_writephy(bp, phy_id, location, val);
-+}
-+
- static int b44_phy_reset(struct b44 *bp)
- {
- u32 val;
-@@ -523,10 +542,12 @@ static void b44_check_phy(struct b44 *bp
-
- if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
- bp->flags |= B44_FLAG_100_BASE_T;
-- bp->flags |= B44_FLAG_FULL_DUPLEX;
- if (!netif_carrier_ok(bp->dev)) {
- u32 val = br32(bp, B44_TX_CTRL);
-- val |= TX_CTRL_DUPLEX;
-+ if (bp->flags & B44_FLAG_FULL_DUPLEX)
-+ val |= TX_CTRL_DUPLEX;
-+ else
-+ val &= ~TX_CTRL_DUPLEX;
- bw32(bp, B44_TX_CTRL, val);
- netif_carrier_on(bp->dev);
- b44_link_report(bp);
-@@ -1805,6 +1826,11 @@ static int b44_get_settings(struct net_d
- {
- struct b44 *bp = netdev_priv(dev);
-
-+ if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
-+ BUG_ON(!bp->phydev);
-+ return phy_ethtool_gset(bp->phydev, cmd);
-+ }
-+
- cmd->supported = (SUPPORTED_Autoneg);
- cmd->supported |= (SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
-@@ -1846,7 +1872,23 @@ static int b44_get_settings(struct net_d
- static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
- {
- struct b44 *bp = netdev_priv(dev);
-- u32 speed = ethtool_cmd_speed(cmd);
-+ u32 speed;
-+ int ret;
-+
-+ if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
-+ BUG_ON(!bp->phydev);
-+ spin_lock_irq(&bp->lock);
-+ if (netif_running(dev))
-+ b44_setup_phy(bp);
-+
-+ ret = phy_ethtool_sset(bp->phydev, cmd);
-+
-+ spin_unlock_irq(&bp->lock);
-+
-+ return ret;
-+ }
-+
-+ speed = ethtool_cmd_speed(cmd);
-
- /* We do not support gigabit. */
- if (cmd->autoneg == AUTONEG_ENABLE) {
-@@ -2076,7 +2118,6 @@ static const struct ethtool_ops b44_etht
-
- static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
- {
-- struct mii_ioctl_data *data = if_mii(ifr);
- struct b44 *bp = netdev_priv(dev);
- int err = -EINVAL;
-
-@@ -2084,7 +2125,12 @@ static int b44_ioctl(struct net_device *
- goto out;
-
- spin_lock_irq(&bp->lock);
-- err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
-+ if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
-+ BUG_ON(!bp->phydev);
-+ err = phy_mii_ioctl(bp->phydev, ifr, cmd);
-+ } else {
-+ err = generic_mii_ioctl(&bp->mii_if, if_mii(ifr), cmd, NULL);
-+ }
- spin_unlock_irq(&bp->lock);
- out:
- return err;
-@@ -2146,6 +2192,127 @@ static const struct net_device_ops b44_n
- #endif
- };
-
-+static void b44_adjust_link(struct net_device *dev)
-+{
-+ struct b44 *bp = netdev_priv(dev);
-+ struct phy_device *phydev = bp->phydev;
-+ bool status_changed = 0;
-+
-+ BUG_ON(!phydev);
-+
-+ if (bp->old_link != phydev->link) {
-+ status_changed = 1;
-+ bp->old_link = phydev->link;
-+ }
-+
-+ /* reflect duplex change */
-+ if (phydev->link) {
-+ if ((phydev->duplex == DUPLEX_HALF) &&
-+ (bp->flags & B44_FLAG_FULL_DUPLEX)) {
-+ status_changed = 1;
-+ bp->flags &= ~B44_FLAG_FULL_DUPLEX;
-+ } else if ((phydev->duplex == DUPLEX_FULL) &&
-+ !(bp->flags & B44_FLAG_FULL_DUPLEX)) {
-+ status_changed = 1;
-+ bp->flags |= B44_FLAG_FULL_DUPLEX;
-+ }
-+ }
-+
-+ if (status_changed) {
-+ b44_check_phy(bp);
-+ phy_print_status(phydev);
-+ }
-+}
-+
-+static int b44_register_phy_one(struct b44 *bp)
-+{
-+ struct mii_bus *mii_bus;
-+ struct ssb_device *sdev = bp->sdev;
-+ struct phy_device *phydev;
-+ char bus_id[MII_BUS_ID_SIZE + 3];
-+ int err;
-+
-+ mii_bus = mdiobus_alloc();
-+ if (!mii_bus) {
-+ dev_err(sdev->dev, "mdiobus_alloc() failed\n");
-+ err = -ENOMEM;
-+ goto err_out;
-+ }
-+
-+ mii_bus->priv = bp;
-+ mii_bus->read = b44_mdio_read_phylib;
-+ mii_bus->write = b44_mdio_write_phylib;
-+ mii_bus->name = "b44_eth_mii";
-+ mii_bus->parent = sdev->dev;
-+ mii_bus->phy_mask = ~(1 << bp->phy_addr);
-+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%x", instance);
-+ mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-+ if (!mii_bus->irq) {
-+ dev_err(sdev->dev, "mii_bus irq allocation failed\n");
-+ err = -ENOMEM;
-+ goto err_out_mdiobus;
-+ }
-+
-+ memset(mii_bus->irq, PHY_POLL, sizeof(int) * PHY_MAX_ADDR);
-+
-+ bp->mii_bus = mii_bus;
-+
-+ err = mdiobus_register(mii_bus);
-+ if (err) {
-+ dev_err(sdev->dev, "failed to register MII bus\n");
-+ goto err_out_mdiobus_irq;
-+ }
-+
-+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, bp->phy_addr);
-+
-+ phydev = phy_connect(bp->dev, bus_id, &b44_adjust_link,
-+ PHY_INTERFACE_MODE_MII);
-+ if (IS_ERR(phydev)) {
-+ dev_err(sdev->dev, "could not attach PHY at %i\n",
-+ bp->phy_addr);
-+ err = PTR_ERR(phydev);
-+ goto err_out_mdiobus_unregister;
-+ }
-+
-+ /* mask with MAC supported features */
-+ phydev->supported &= (SUPPORTED_100baseT_Half |
-+ SUPPORTED_100baseT_Full |
-+ SUPPORTED_Autoneg |
-+ SUPPORTED_MII);
-+ phydev->advertising = phydev->supported;
-+
-+ bp->phydev = phydev;
-+ bp->old_link = 0;
-+ bp->phy_addr = phydev->addr;
-+
-+ dev_info(sdev->dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
-+ phydev->drv->name, dev_name(&phydev->dev));
-+
-+ return 0;
-+
-+err_out_mdiobus_unregister:
-+ mdiobus_unregister(mii_bus);
-+
-+err_out_mdiobus_irq:
-+ kfree(mii_bus->irq);
-+
-+err_out_mdiobus:
-+ mdiobus_free(mii_bus);
-+
-+err_out:
-+ return err;
-+}
-+
-+static void b44_unregister_phy_one(struct b44 *bp)
-+{
-+ struct mii_bus *mii_bus = bp->mii_bus;
-+
-+ phy_disconnect(bp->phydev);
-+ mdiobus_unregister(mii_bus);
-+ kfree(mii_bus->irq);
-+ mdiobus_free(mii_bus);
-+}
-+
- static int b44_init_one(struct ssb_device *sdev,
- const struct ssb_device_id *ent)
- {
-@@ -2246,10 +2413,20 @@ static int b44_init_one(struct ssb_devic
- if (b44_phy_reset(bp) < 0)
- bp->phy_addr = B44_PHY_ADDR_NO_LOCAL_PHY;
-
-+ if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
-+ err = b44_register_phy_one(bp);
-+ if (err) {
-+ dev_err(sdev->dev, "Cannot register PHY, aborting\n");
-+ goto err_out_unregister_netdev;
-+ }
-+ }
-+
- netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
-
- return 0;
-
-+err_out_unregister_netdev:
-+ unregister_netdev(dev);
- err_out_powerdown:
- ssb_bus_may_powerdown(sdev->bus);
-
-@@ -2263,8 +2440,11 @@ out:
- static void b44_remove_one(struct ssb_device *sdev)
- {
- struct net_device *dev = ssb_get_drvdata(sdev);
-+ struct b44 *bp = netdev_priv(dev);
-
- unregister_netdev(dev);
-+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
-+ b44_unregister_phy_one(bp);
- ssb_device_disable(sdev, 0);
- ssb_bus_may_powerdown(sdev->bus);
- free_netdev(dev);
---- a/drivers/net/ethernet/broadcom/b44.h
-+++ b/drivers/net/ethernet/broadcom/b44.h
-@@ -397,6 +397,9 @@ struct b44 {
- u32 tx_pending;
- u8 phy_addr;
- u8 force_copybreak;
-+ struct phy_device *phydev;
-+ struct mii_bus *mii_bus;
-+ int old_link;
- struct mii_if_info mii_if;
- };
-