summaryrefslogtreecommitdiffstats
path: root/drivers/net/designware.c
diff options
context:
space:
mode:
authorTrent Piepho <tpiepho@kymetacorp.com>2015-11-11 20:54:01 +0000
committerSascha Hauer <s.hauer@pengutronix.de>2015-11-13 08:00:19 +0100
commitf0ae0c33f52ced89da080673ca89a3c5f2ea70e6 (patch)
tree03ae39e6c9d0ee2588aea1b96f4e3b9040ea1640 /drivers/net/designware.c
parentc9a3849ec9f5f7356dd61e7e4bf90e3a55cca1cd (diff)
downloadbarebox-f0ae0c33f52ced89da080673ca89a3c5f2ea70e6.tar.gz
barebox-f0ae0c33f52ced89da080673ca89a3c5f2ea70e6.tar.xz
net: designware: Don't hang in reset with powered down phy
The dw MAC requires that all clock domains to be running for it to finish a MAC reset. This include the clock provided by the PHY. If the PHY is powered down, bit BMCR_PDOWN set, then it won't be generating a clock. And so the MAC never comes out of reset. On shutdown, Linux will put the PHY in powerdown mode, so it can easily be the case that the PHY is powered down on boot. See Linux kernel commit 2d871aa07136fe6e576bde63072cf33e2c664e95. Currently the MAC reset is done before the phy is probed. We can't power up the phy until it's probed, so the resets must be in the opposite order. The MAC reset is in device init but the PHY probe is in device open. Device init is done first, always, while open is done later, and only if the device is used. Rather than move the phy probe to init, this moves the MAC reset to open. It seems better to speed up boots that doesn't use ethernet by skipping MAC reset than to slow them down by adding PHY probe. Signed-off-by: Trent Piepho <tpiepho@kymetacorp.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net/designware.c')
-rw-r--r--drivers/net/designware.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 800652760a..966f64f7b6 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -213,12 +213,34 @@ static void descs_init(struct eth_device *dev)
rx_descs_init(dev);
}
+/* Get PHY out of power saving mode. If this is needed elsewhere then
+ * consider making it part of phy-core and adding a resume method to
+ * the phy device ops. */
+static int phy_resume(struct phy_device *phydev)
+{
+ int bmcr;
+
+ bmcr = phy_read(phydev, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+ if (bmcr & BMCR_PDOWN) {
+ bmcr &= ~BMCR_PDOWN;
+ return phy_write(phydev, MII_BMCR, bmcr);
+ }
+ return 0;
+}
+
static int dwc_ether_init(struct eth_device *dev)
{
struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ /* Before we reset the mac, we must insure the PHY is not powered down
+ * as the dw controller needs all clock domains to be running, including
+ * the PHY clock, to come out of a mac reset. */
+ phy_resume(dev->phydev);
+
if (mac_reset(dev) < 0)
return -1;
@@ -275,6 +297,8 @@ static int dwc_ether_open(struct eth_device *dev)
if (ret)
return ret;
+ dwc_ether_init(dev);
+
descs_init(dev);
/*
@@ -468,7 +492,6 @@ static int dwc_ether_probe(struct device_d *dev)
edev->priv = priv;
edev->parent = dev;
- edev->init = dwc_ether_init;
edev->open = dwc_ether_open;
edev->send = dwc_ether_send;
edev->recv = dwc_ether_rx;