* [PATCH v3 0/8] b44: add support for external PHY
@ 2013-12-20 1:16 Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 1/8] b44: check register instead of PHY address to detect " Hauke Mehrtens
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
This adds support for an external phy connected to the mac controlled
by b44. This is used on home routers of the BCM47xx line where this MAC
core was used and is contended to an external switch core through MII.
These patches are in OpenWrt for some time and are tested by different
users with different devices.
The publicly available Programmer's Reference Guide for some of these
chips help making this patch it would be nice to have such a
documentation for more Broadcom Chips like some SoCs.
https://www.broadcom.com/collateral/pg/440X-PG02-R.pdf
v3:
- remove changes to the fixed phy driver
- call fixed_phy_add() in arch/mips/bcm47xx/setup.c before the fixed
phy gets registered
v2:
- add fixed phy driver patch
- use fixed phy driver in b44
- some smaller changes and typos
Hauke Mehrtens (8):
b44: check register instead of PHY address to detect external PHY
b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY
b44: abort when no PHY is available at all
b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii
b44: add phylib support
b44: activate PHY when MAC is off
b44: do not set PHY address to 30 for every ext PHY
b44: use fixed PHY device if we do not find any
arch/mips/bcm47xx/setup.c | 10 ++
drivers/net/ethernet/broadcom/Kconfig | 1 +
drivers/net/ethernet/broadcom/b44.c | 250 ++++++++++++++++++++++++++++++---
drivers/net/ethernet/broadcom/b44.h | 15 +-
4 files changed, 250 insertions(+), 26 deletions(-)
--
1.7.10.4
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/8] b44: check register instead of PHY address to detect external PHY
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 2/8] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY Hauke Mehrtens
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
The Ethernet core supported by b44 supports an internal PHY integrated
into the mac core, which is supported by the b44 driver and an external
PHY to which the mac core is connected. This external PHY could be a
switch connected through MII, which is often the case when this core is
used on home routers. The usage of an external PHY was assumed when the
PHY address 30 was used and an internal PHY was assumed when the PHY
address was different. To verify that b44_phy_reset() was called and
checked if it worked, otherwise PHY address 30 was assumed, an external
PHY. It is better to check the register which says which PHY is
connected to the MAC instead of checking the PHY address.
The interface to an external PHY was only activated when this register
was set.
This also changes B44_FLAG_INTERNAL_PHY to B44_FLAG_EXTERNAL_PHY, it is
easier to check.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/b44.c | 18 +++++++++---------
drivers/net/ethernet/broadcom/b44.h | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 90e54d5..3c7909e 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -284,7 +284,7 @@ static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
{
- if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
return 0;
return __b44_readphy(bp, bp->phy_addr, reg, val);
@@ -292,7 +292,7 @@ static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
{
- if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
return 0;
return __b44_writephy(bp, bp->phy_addr, reg, val);
@@ -321,7 +321,7 @@ static int b44_phy_reset(struct b44 *bp)
u32 val;
int err;
- if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
return 0;
err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
if (err)
@@ -423,7 +423,7 @@ static int b44_setup_phy(struct b44 *bp)
b44_wap54g10_workaround(bp);
- if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
return 0;
if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
goto out;
@@ -521,7 +521,7 @@ static void b44_check_phy(struct b44 *bp)
{
u32 bmsr, aux;
- if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+ 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)) {
@@ -1315,7 +1315,7 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind)
if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
br32(bp, B44_ENET_CTRL);
- bp->flags &= ~B44_FLAG_INTERNAL_PHY;
+ bp->flags |= B44_FLAG_EXTERNAL_PHY;
} else {
u32 val = br32(bp, B44_DEVCTRL);
@@ -1324,7 +1324,7 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind)
br32(bp, B44_DEVCTRL);
udelay(100);
}
- bp->flags |= B44_FLAG_INTERNAL_PHY;
+ bp->flags &= ~B44_FLAG_EXTERNAL_PHY;
}
}
@@ -1828,8 +1828,8 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
DUPLEX_FULL : DUPLEX_HALF;
cmd->port = 0;
cmd->phy_address = bp->phy_addr;
- cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
- XCVR_INTERNAL : XCVR_EXTERNAL;
+ cmd->transceiver = (bp->flags & B44_FLAG_EXTERNAL_PHY) ?
+ XCVR_EXTERNAL : XCVR_INTERNAL;
cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
AUTONEG_DISABLE : AUTONEG_ENABLE;
if (cmd->autoneg == AUTONEG_ENABLE)
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 8993d72..8ed7d6b 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -376,7 +376,7 @@ struct b44 {
#define B44_FLAG_ADV_10FULL 0x02000000
#define B44_FLAG_ADV_100HALF 0x04000000
#define B44_FLAG_ADV_100FULL 0x08000000
-#define B44_FLAG_INTERNAL_PHY 0x10000000
+#define B44_FLAG_EXTERNAL_PHY 0x10000000
#define B44_FLAG_RX_RING_HACK 0x20000000
#define B44_FLAG_TX_RING_HACK 0x40000000
#define B44_FLAG_WOL_ENABLE 0x80000000
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/8] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 1/8] b44: check register instead of PHY address to detect " Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 3/8] b44: abort when no PHY is available at all Hauke Mehrtens
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
The PHY address 30 means there is no local PHY, but there could be an
external PHY like a switch connected via MII. This is the case on most
embedded home routers where this driver is used.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/b44.c | 2 +-
drivers/net/ethernet/broadcom/b44.h | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 3c7909e..5c05d15 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2237,7 +2237,7 @@ static int b44_init_one(struct ssb_device *sdev,
/* do a phy reset to test if there is an active phy */
if (b44_phy_reset(bp) < 0)
- bp->phy_addr = B44_PHY_ADDR_NO_PHY;
+ bp->phy_addr = B44_PHY_ADDR_NO_LOCAL_PHY;
netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 8ed7d6b..57e5357 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -280,9 +280,9 @@ struct ring_info {
dma_addr_t mapping;
};
-#define B44_MCAST_TABLE_SIZE 32
-#define B44_PHY_ADDR_NO_PHY 30
-#define B44_MDC_RATIO 5000000
+#define B44_MCAST_TABLE_SIZE 32
+#define B44_PHY_ADDR_NO_LOCAL_PHY 30 /* no local phy regs */
+#define B44_MDC_RATIO 5000000
#define B44_STAT_REG_DECLARE \
_B44(tx_good_octets) \
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 3/8] b44: abort when no PHY is available at all
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 1/8] b44: check register instead of PHY address to detect " Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 2/8] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 4/8] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii Hauke Mehrtens
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
When the phy address is 31, this means that there is no PHY connected
to this MAC at all, no internal and no external PHY. Reading these PHY
registers causes a system reset on some routers.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/b44.c | 6 ++++++
drivers/net/ethernet/broadcom/b44.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 5c05d15..09e9e97 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2206,6 +2206,12 @@ static int b44_init_one(struct ssb_device *sdev,
goto err_out_powerdown;
}
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+ dev_err(sdev->dev, "No PHY present on this MAC, aborting\n");
+ err = -ENODEV;
+ goto err_out_powerdown;
+ }
+
bp->mii_if.dev = dev;
bp->mii_if.mdio_read = b44_mii_read;
bp->mii_if.mdio_write = b44_mii_write;
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 57e5357..4b0c5d2 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -282,6 +282,7 @@ struct ring_info {
#define B44_MCAST_TABLE_SIZE 32
#define B44_PHY_ADDR_NO_LOCAL_PHY 30 /* no local phy regs */
+#define B44_PHY_ADDR_NO_PHY 31 /* no phy present at all */
#define B44_MDC_RATIO 5000000
#define B44_STAT_REG_DECLARE \
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 4/8] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (2 preceding siblings ...)
2013-12-20 1:16 ` [PATCH v3 3/8] b44: abort when no PHY is available at all Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 5/8] b44: add phylib support Hauke Mehrtens
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
The next patch will add these functions for phylib, and we should
rename the old ones before. This now indicates that these functions are
used for the mdio registers and on the mii interface.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/b44.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 09e9e97..40a9de2 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -299,7 +299,7 @@ static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
}
/* miilib interface */
-static int b44_mii_read(struct net_device *dev, int phy_id, int location)
+static int b44_mdio_read_mii(struct net_device *dev, int phy_id, int location)
{
u32 val;
struct b44 *bp = netdev_priv(dev);
@@ -309,8 +309,8 @@ static int b44_mii_read(struct net_device *dev, int phy_id, int location)
return val;
}
-static void b44_mii_write(struct net_device *dev, int phy_id, int location,
- int val)
+static void b44_mdio_write_mii(struct net_device *dev, int phy_id, int location,
+ int val)
{
struct b44 *bp = netdev_priv(dev);
__b44_writephy(bp, phy_id, location, val);
@@ -2213,8 +2213,8 @@ static int b44_init_one(struct ssb_device *sdev,
}
bp->mii_if.dev = dev;
- bp->mii_if.mdio_read = b44_mii_read;
- bp->mii_if.mdio_write = b44_mii_write;
+ bp->mii_if.mdio_read = b44_mdio_read_mii;
+ bp->mii_if.mdio_write = b44_mdio_write_mii;
bp->mii_if.phy_id = bp->phy_addr;
bp->mii_if.phy_id_mask = 0x1f;
bp->mii_if.reg_num_mask = 0x1f;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 5/8] b44: add phylib support
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (3 preceding siblings ...)
2013-12-20 1:16 ` [PATCH v3 4/8] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 6/8] b44: activate PHY when MAC is off Hauke Mehrtens
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
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>
---
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(-)
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 2fa5b86..3f97d9f 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -23,6 +23,7 @@ config B44
depends on SSB_POSSIBLE && HAS_DMA
select SSB
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
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 40a9de2..7b1e71d 100644
--- 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 net_device *dev, int phy_id, int location,
__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_device *dev, struct ethtool_cmd *cmd)
{
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_device *dev, struct ethtool_cmd *cmd)
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_ethtool_ops = {
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 *dev, struct ifreq *ifr, int cmd)
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_netdev_ops = {
#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)
{
@@ -2245,10 +2412,20 @@ static int b44_init_one(struct ssb_device *sdev,
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);
@@ -2262,8 +2439,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);
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 4b0c5d2..de81639 100644
--- 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;
};
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 6/8] b44: activate PHY when MAC is off
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (4 preceding siblings ...)
2013-12-20 1:16 ` [PATCH v3 5/8] b44: add phylib support Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 7/8] b44: do not set PHY address to 30 for every ext PHY Hauke Mehrtens
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
Without this patch we can not access the PHY when the MAC is switched
off. This PHY access is needed to configure the switch, which is done
through PHY registers.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/b44.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 7b1e71d..d17561b 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1360,7 +1360,10 @@ static void b44_halt(struct b44 *bp)
bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
/* now reset the chip, but without enabling the MAC&PHY
* part of it. This has to be done _after_ we shut down the PHY */
- b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+ b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+ else
+ b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
}
/* bp->lock is held. */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 7/8] b44: do not set PHY address to 30 for every ext PHY
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (5 preceding siblings ...)
2013-12-20 1:16 ` [PATCH v3 6/8] b44: activate PHY when MAC is off Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 8/8] b44: use fixed PHY device if we do not find any Hauke Mehrtens
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
b44_phy_reset() will fail for an external PHY and only work with the
internal PHY, this was an old workaround when the detection of an
external switch based on the PHY address failed and it is not needed
any more.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
drivers/net/ethernet/broadcom/b44.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index d17561b..839dd90 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2412,8 +2412,11 @@ static int b44_init_one(struct ssb_device *sdev,
b44_chip_reset(bp, B44_CHIP_RESET_FULL);
/* do a phy reset to test if there is an active phy */
- if (b44_phy_reset(bp) < 0)
- bp->phy_addr = B44_PHY_ADDR_NO_LOCAL_PHY;
+ err = b44_phy_reset(bp);
+ if (err < 0) {
+ dev_err(sdev->dev, "phy reset failed\n");
+ goto err_out_unregister_netdev;
+ }
if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
err = b44_register_phy_one(bp);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 8/8] b44: use fixed PHY device if we do not find any
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (6 preceding siblings ...)
2013-12-20 1:16 ` [PATCH v3 7/8] b44: do not set PHY address to 30 for every ext PHY Hauke Mehrtens
@ 2013-12-20 1:16 ` Hauke Mehrtens
2013-12-20 2:02 ` [PATCH v3 0/8] b44: add support for external PHY Florian Fainelli
2013-12-21 1:49 ` David Miller
9 siblings, 0 replies; 11+ messages in thread
From: Hauke Mehrtens @ 2013-12-20 1:16 UTC (permalink / raw)
To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens
The ADM6996L switch and some Broadcom switches with two MII interfaces
like the BCM5325F connected to two MACs on the SoC, used on some
routers do not return a valid value when reading the PHY id register
and Linux thinks there is no PHY at all, but that is wrong.
This patch registers a fixed phy in the arch code and then searches it
when there is no other phy in the Ethernet driver code.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
arch/mips/bcm47xx/setup.c | 10 ++++++++++
drivers/net/ethernet/broadcom/b44.c | 16 +++++++++++++++-
drivers/net/ethernet/broadcom/b44.h | 3 +++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 1f30571..9057728 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -28,6 +28,9 @@
#include <linux/export.h>
#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
#include <linux/bcma/bcma_soc.h>
@@ -225,6 +228,12 @@ void __init plat_mem_setup(void)
bcm47xx_board_detect();
}
+static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
+ .link = 1,
+ .speed = SPEED_100,
+ .duplex = DUPLEX_FULL,
+};
+
static int __init bcm47xx_register_bus_complete(void)
{
switch (bcm47xx_bus_type) {
@@ -239,6 +248,7 @@ static int __init bcm47xx_register_bus_complete(void)
break;
#endif
}
+ fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
return 0;
}
device_initcall(bcm47xx_register_bus_complete);
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 839dd90..1f7b5aa 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2233,6 +2233,7 @@ static int b44_register_phy_one(struct b44 *bp)
struct ssb_device *sdev = bp->sdev;
struct phy_device *phydev;
char bus_id[MII_BUS_ID_SIZE + 3];
+ struct ssb_sprom *sprom = &sdev->bus->sprom;
int err;
mii_bus = mdiobus_alloc();
@@ -2266,7 +2267,20 @@ static int b44_register_phy_one(struct b44 *bp)
goto err_out_mdiobus_irq;
}
- snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, bp->phy_addr);
+ if (!bp->mii_bus->phy_map[bp->phy_addr] &&
+ (sprom->boardflags_lo & (B44_BOARDFLAG_ROBO | B44_BOARDFLAG_ADM))) {
+
+ dev_info(sdev->dev,
+ "could not find PHY at %i, use fixed one\n",
+ bp->phy_addr);
+
+ bp->phy_addr = 0;
+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, "fixed-0",
+ bp->phy_addr);
+ } else {
+ 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);
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index de81639..3e9c3fc 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -345,6 +345,9 @@ B44_STAT_REG_DECLARE
struct u64_stats_sync syncp;
};
+#define B44_BOARDFLAG_ROBO 0x0010 /* Board has robo switch */
+#define B44_BOARDFLAG_ADM 0x0080 /* Board has ADMtek switch */
+
struct ssb_device;
struct b44 {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 0/8] b44: add support for external PHY
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (7 preceding siblings ...)
2013-12-20 1:16 ` [PATCH v3 8/8] b44: use fixed PHY device if we do not find any Hauke Mehrtens
@ 2013-12-20 2:02 ` Florian Fainelli
2013-12-21 1:49 ` David Miller
9 siblings, 0 replies; 11+ messages in thread
From: Florian Fainelli @ 2013-12-20 2:02 UTC (permalink / raw)
To: Hauke Mehrtens; +Cc: David Miller, zambrano, netdev
2013/12/19 Hauke Mehrtens <hauke@hauke-m.de>:
> This adds support for an external phy connected to the mac controlled
> by b44. This is used on home routers of the BCM47xx line where this MAC
> core was used and is contended to an external switch core through MII.
> These patches are in OpenWrt for some time and are tested by different
> users with different devices.
>
> The publicly available Programmer's Reference Guide for some of these
> chips help making this patch it would be nice to have such a
> documentation for more Broadcom Chips like some SoCs.
> https://www.broadcom.com/collateral/pg/440X-PG02-R.pdf
>
> v3:
> - remove changes to the fixed phy driver
> - call fixed_phy_add() in arch/mips/bcm47xx/setup.c before the fixed
> phy gets registered
Thanks Hauke, this looks great now!
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
>
> v2:
> - add fixed phy driver patch
> - use fixed phy driver in b44
> - some smaller changes and typos
>
> Hauke Mehrtens (8):
> b44: check register instead of PHY address to detect external PHY
> b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY
> b44: abort when no PHY is available at all
> b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii
> b44: add phylib support
> b44: activate PHY when MAC is off
> b44: do not set PHY address to 30 for every ext PHY
> b44: use fixed PHY device if we do not find any
>
> arch/mips/bcm47xx/setup.c | 10 ++
> drivers/net/ethernet/broadcom/Kconfig | 1 +
> drivers/net/ethernet/broadcom/b44.c | 250 ++++++++++++++++++++++++++++++---
> drivers/net/ethernet/broadcom/b44.h | 15 +-
> 4 files changed, 250 insertions(+), 26 deletions(-)
>
> --
> 1.7.10.4
>
--
Florian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 0/8] b44: add support for external PHY
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
` (8 preceding siblings ...)
2013-12-20 2:02 ` [PATCH v3 0/8] b44: add support for external PHY Florian Fainelli
@ 2013-12-21 1:49 ` David Miller
9 siblings, 0 replies; 11+ messages in thread
From: David Miller @ 2013-12-21 1:49 UTC (permalink / raw)
To: hauke; +Cc: zambrano, netdev, f.fainelli
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Fri, 20 Dec 2013 02:16:05 +0100
> This adds support for an external phy connected to the mac controlled
> by b44. This is used on home routers of the BCM47xx line where this MAC
> core was used and is contended to an external switch core through MII.
> These patches are in OpenWrt for some time and are tested by different
> users with different devices.
>
> The publicly available Programmer's Reference Guide for some of these
> chips help making this patch it would be nice to have such a
> documentation for more Broadcom Chips like some SoCs.
> https://www.broadcom.com/collateral/pg/440X-PG02-R.pdf
>
> v3:
> - remove changes to the fixed phy driver
> - call fixed_phy_add() in arch/mips/bcm47xx/setup.c before the fixed
> phy gets registered
>
> v2:
> - add fixed phy driver patch
> - use fixed phy driver in b44
> - some smaller changes and typos
Series applied, thanks.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2013-12-21 1:49 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-20 1:16 [PATCH v3 0/8] b44: add support for external PHY Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 1/8] b44: check register instead of PHY address to detect " Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 2/8] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 3/8] b44: abort when no PHY is available at all Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 4/8] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 5/8] b44: add phylib support Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 6/8] b44: activate PHY when MAC is off Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 7/8] b44: do not set PHY address to 30 for every ext PHY Hauke Mehrtens
2013-12-20 1:16 ` [PATCH v3 8/8] b44: use fixed PHY device if we do not find any Hauke Mehrtens
2013-12-20 2:02 ` [PATCH v3 0/8] b44: add support for external PHY Florian Fainelli
2013-12-21 1:49 ` David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).