Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc81b9be authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "net: stmmac: Add support for Micrel PHY interrupt"

parents 0bf3d445 0f3e11d4
Loading
Loading
Loading
Loading
+47 −9
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#include <linux/debugfs.h>
#include <linux/dma-iommu.h>
#include <linux/iommu.h>

#include <linux/micrel_phy.h>

#include "stmmac.h"
#include "stmmac_platform.h"
@@ -102,6 +102,15 @@
#define LINK_DOWN_STATE 0x800
#define LINK_UP_STATE 0x400

#define MICREL_PHY_ID PHY_ID_KSZ9031
#define DWC_ETH_QOS_MICREL_PHY_INTCS 0x1b
#define DWC_ETH_QOS_MICREL_PHY_CTL 0x1f
#define DWC_ETH_QOS_MICREL_INTR_LEVEL 0x4000
#define DWC_ETH_QOS_BASIC_STATUS     0x0001
#define LINK_STATE_MASK 0x4
#define AUTONEG_STATE_MASK 0x20
#define MICREL_LINK_UP_INTR_STATUS BIT(0)

bool phy_intr_en;

struct emac_emb_smmu_cb_ctx emac_emb_smmu_ctx = {0};
@@ -561,8 +570,36 @@ static void ethqos_handle_phy_interrupt(struct qcom_ethqos *ethqos)

	struct net_device *dev = platform_get_drvdata(pdev);
	struct stmmac_priv *priv = netdev_priv(dev);

	phy_intr_status = ethqos_mdio_read(priv, priv->plat->phy_addr,
	int micrel_intr_status = 0;

	if (priv->phydev && (priv->phydev->phy_id &
	    priv->phydev->drv->phy_id_mask)
	    == MICREL_PHY_ID) {
		phy_intr_status = ethqos_mdio_read(priv,
						   priv->plat->phy_addr,
						   DWC_ETH_QOS_BASIC_STATUS);
		ETHQOSDBG("Basic Status Reg (%#x) = %#x\n",
			  DWC_ETH_QOS_BASIC_STATUS, phy_intr_status);
		micrel_intr_status = ethqos_mdio_read(priv,
						      priv->plat->phy_addr,
						      DWC_ETH_QOS_MICREL_PHY_INTCS);
		ETHQOSDBG("MICREL PHY Intr EN Reg (%#x) = %#x\n",
			  DWC_ETH_QOS_MICREL_PHY_INTCS, micrel_intr_status);

		/* Interrupt received for link state change */
		if (phy_intr_status & LINK_STATE_MASK) {
			if (micrel_intr_status & MICREL_LINK_UP_INTR_STATUS)
				ETHQOSDBG("Intr for link UP state\n");
			phy_mac_interrupt(priv->phydev);
		} else if (!(phy_intr_status & LINK_STATE_MASK)) {
			ETHQOSDBG("Intr for link DOWN state\n");
			phy_mac_interrupt(priv->phydev);
		} else if (!(phy_intr_status & AUTONEG_STATE_MASK)) {
			ETHQOSDBG("Intr for link down with auto-neg err\n");
		}
	} else {
		phy_intr_status =
		 ethqos_mdio_read(priv, priv->plat->phy_addr,
				  DWC_ETH_QOS_PHY_INTR_STATUS);

		if (phy_intr_status & LINK_UP_STATE)
@@ -570,6 +607,7 @@ static void ethqos_handle_phy_interrupt(struct qcom_ethqos *ethqos)
		else if (phy_intr_status & LINK_DOWN_STATE)
			phylink_mac_change(priv->phylink, LINK_DOWN);
	}
}

static void ethqos_defer_phy_isr_work(struct work_struct *work)
{
+1 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ struct stmmac_priv {
	struct mac_device_info *hw;
	int (*hwif_quirks)(struct stmmac_priv *priv);
	struct mutex lock;
	struct phy_device *phydev;

	/* RX Queue */
	struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES];
+27 −14
Original line number Diff line number Diff line
@@ -95,6 +95,11 @@ module_param(eee_timer, int, 0644);
MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))

#define DWC_ETH_QOS_MICREL_PHY_CTL 0x1f
#define DWC_ETH_QOS_MICREL_INTR_LEVEL 0x4000
#define PHY_ID_KSZ9031		0x00221620
#define MICREL_PHY_ID PHY_ID_KSZ9031

/* By default the driver will use the ring mode to manage tx and rx descriptors,
 * but allow user to force to use the chain instead of the ring
 */
@@ -1022,27 +1027,35 @@ static int stmmac_init_phy(struct net_device *dev)
	 */
	if (!node || ret) {
		int addr = priv->plat->phy_addr;
		struct phy_device *phydev;

		phydev = mdiobus_get_phy(priv->mii, addr);
		if (!phydev) {
		priv->phydev = mdiobus_get_phy(priv->mii, addr);
		if (!priv->phydev) {
			netdev_err(priv->dev, "no phy at addr %d\n", addr);
			return -ENODEV;
		}
		ret = phylink_connect_phy(priv->phylink, priv->phydev);
		if (phy_intr_en) {
			phydev->irq = PHY_IGNORE_INTERRUPT;
			phydev->interrupts =  PHY_INTERRUPT_ENABLED;
			priv->phydev->irq = PHY_IGNORE_INTERRUPT;
			priv->phydev->interrupts =  PHY_INTERRUPT_ENABLED;
			if (priv->phydev->drv->ack_interrupt &&
			    !priv->phydev->drv->ack_interrupt(priv->phydev)) {
				pr_info(" qcom-ethqos: %s ack_interrupt successful aftre connect\n",
					__func__);
			} else {
				pr_err(" qcom-ethqos: %s ack_interrupt failed aftre connect\n",
				       __func__);
			}

			if (phydev->drv && phydev->drv->config_intr &&
			    !phydev->drv->config_intr(phydev)) {
				pr_debug(" qcom-ethqos: %s config_phy_intr successful\n",
			if (priv->phydev->drv &&
			    priv->phydev->drv->config_intr &&
			    !priv->phydev->drv->config_intr(priv->phydev)) {
				pr_err(" qcom-ethqos: %s config_phy_intr successful aftre connect\n",
				       __func__);
			}
		} else {
		pr_err("stmmac phy polling mode\n");
		phydev->irq = PHY_POLL;
			pr_info("stmmac phy polling mode\n");
			priv->phydev->irq = PHY_POLL;
		}
		ret = phylink_connect_phy(priv->phylink, phydev);
	}

	return ret;