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

Commit d4182881 authored by Alok Chauhan's avatar Alok Chauhan
Browse files

msm: emac: Add handling of ephy RST pin



RST pin should be treated differently from MDIO pins.
Improper toggling of RST pin can cause the spurious
Interrupts storms from ePHY.

Add handling of RST pin in code and add the logic to
Reset ePHY as well.

Change-Id: Ib4c0ee29d8e53c182af1ba8aadd89ef5e4aa21fb
Signed-off-by: default avatarAlok Chauhan <alokc@codeaurora.org>
parent 863a7de4
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -686,7 +686,7 @@
		};

		emac0 {
			emac0_active: emac0_active {
			emac0_mdio_active: emac0_mdio_active {
				/* active state */
				mux {
					/* MDC MDIO */
@@ -701,7 +701,7 @@
				};
			};

			emac0_sleep: emac0_sleep {
			emac0_mdio_sleep: emac0_mdio_sleep {
				/* suspended state */
				mux {
					/* MDC MDIO */
@@ -716,25 +716,26 @@
				};
			};

			emac0_rst_active: emac0_rst_active {
			emac0_ephy_active: emac0_ephy_active {
				/* active state */
				mux {
					/* ETH RST */
					/* EPHY RST */
					pins = "gpio29";
					function = "gpio";
				};

				config {
					pins = "gpio29";
					drive-strength = <16>; /* 8 MA */
					drive-strength = <16>; /* 16 MA */
					bias-pull-up;
					output-high;
				};
			};

			emac0_rst_sleep: emac0_rst_sleep {
			emac0_ephy_sleep: emac0_ephy_sleep {
				/* suspended state */
				mux {
					/* ETH RST */
					/* EPHY RST */
					pins = "gpio29";
					function = "gpio";
				};
@@ -742,7 +743,8 @@
				config {
					pins = "gpio29";
					drive-strength = <2>; /* 2 MA */
					bias-pull-down;
					bias-disable;
					output-low;
				};
			};
		};
+6 −3
Original line number Diff line number Diff line
@@ -1342,9 +1342,12 @@
			 <&clock_gcc clk_gcc_emac_0_sys_clk>;
		clock-names = "axi_clk", "cfg_ahb_clk", "125m_clk",
			"25m_clk", "tx_clk", "rx_clk", "sys_clk";
		pinctrl-names = "emac_active", "emac_sleep";
		pinctrl-0 = <&emac0_active &emac0_rst_active>;
		pinctrl-1 = <&emac0_sleep &emac0_rst_sleep>;
		pinctrl-names = "emac_mdio_active", "emac_mdio_sleep",
			"emac_ephy_active", "emac_ephy_sleep";
		pinctrl-0 = <&emac0_mdio_active>;
		pinctrl-1 = <&emac0_mdio_sleep>;
		pinctrl-2 = <&emac0_ephy_active>;
		pinctrl-3 = <&emac0_ephy_sleep>;
		qcom,emac-tstamp-en;
		qcom,emac-ptp-frac-ns-adj = <125000000 1>;
		phy-mode = "sgmii";
+6 −4
Original line number Diff line number Diff line
@@ -723,10 +723,12 @@ struct emac_adapter {
	u16             msg_enable;
	unsigned long   flags;
	struct pinctrl	*pinctrl;
	struct pinctrl_state	*pins_active;
	struct pinctrl_state	*pins_sleep;
	int	(*gpio_on)(struct emac_adapter *adpt);
	int	(*gpio_off)(struct emac_adapter *adpt);
	struct pinctrl_state	*mdio_pins_active;
	struct pinctrl_state	*mdio_pins_sleep;
	struct pinctrl_state	*ephy_pins_active;
	struct pinctrl_state	*ephy_pins_sleep;
	int	(*gpio_on)(struct emac_adapter *adpt, bool mdio, bool ephy);
	int	(*gpio_off)(struct emac_adapter *adpt, bool mdio, bool ephy);
	struct wakeup_source link_wlock;
};

+121 −47
Original line number Diff line number Diff line
@@ -70,8 +70,10 @@ static struct of_device_id emac_dt_match[];

#define EMAC_SKB_CB(skb) ((struct emac_skb_cb *)(skb)->cb)

#define EMAC_PINCTRL_STATE_ACTIVE "emac_active"
#define EMAC_PINCTRL_STATE_SLEEP "emac_sleep"
#define EMAC_PINCTRL_STATE_MDIO_ACTIVE "emac_mdio_active"
#define EMAC_PINCTRL_STATE_MDIO_SLEEP  "emac_mdio_sleep"
#define EMAC_PINCTRL_STATE_EPHY_ACTIVE "emac_ephy_active"
#define EMAC_PINCTRL_STATE_EPHY_SLEEP  "emac_ephy_sleep"

#define EMAC_VREG1_VOLTAGE	1250000
#define EMAC_VREG2_VOLTAGE	1800000
@@ -1873,58 +1875,110 @@ static int emac_change_mtu(struct net_device *netdev, int new_mtu)
	return 0;
}

static inline int msm_emac_request_gpio_on(struct emac_adapter *adpt)
static inline int msm_emac_request_gpio_on(struct emac_adapter *adpt,
					   bool mdio, bool ephy)
{
	int i = 0;
	int result = 0;
	struct emac_phy *phy = &adpt->phy;

	if (phy->external) {
		for (i = 0; phy->uses_gpios && i < EMAC_GPIO_CNT; i++) {
			result = gpio_request(adpt->gpio[i], emac_gpio_name[i]);
			if (result) {
			emac_err(adpt, "error:%d on gpio_request(%d:%s)\n",
				emac_err(adpt,
					 "error:%d on gpio_request(%d:%s)\n",
					 result, adpt->gpio[i],
					 emac_gpio_name[i]);

				while (--i >= 0)
					gpio_free(adpt->gpio[i]);
				goto error;
			}
		}
	}
	return 0;
error:
	return result;
}

static inline int msm_emac_request_gpio_off(struct emac_adapter *adpt)
static inline int msm_emac_request_gpio_off(struct emac_adapter *adpt,
					    bool mdio, bool ephy)
{
	int i = 0;
	struct emac_phy *phy = &adpt->phy;

	if (phy->external) {
		for (i = 0; phy->uses_gpios && i < EMAC_GPIO_CNT; i++)
			gpio_free(adpt->gpio[i]);
	}
	return 0;
}

static inline int msm_emac_request_pinctrl_on(struct emac_adapter *adpt)
static inline int msm_emac_request_pinctrl_on(struct emac_adapter *adpt,
					      bool mdio, bool ephy)
{
	int result = 0;
	int ret    = 0;
	struct emac_phy *phy = &adpt->phy;

	result = pinctrl_select_state(adpt->pinctrl, adpt->pins_active);
	if (phy->external) {
		if (mdio) {
			result = pinctrl_select_state(adpt->pinctrl,
						      adpt->mdio_pins_active);
			if (result)
		emac_err(adpt, "error:%d Can not set %s pins\n",
			 result, EMAC_PINCTRL_STATE_ACTIVE);
	return result;
				emac_err(adpt,
					 "error:%d Can not switch on %s pins\n",
					 result,
					 EMAC_PINCTRL_STATE_MDIO_ACTIVE);
			ret = result;
		}

		if (ephy) {
			result = pinctrl_select_state(adpt->pinctrl,
						      adpt->ephy_pins_active);
			if (result)
				emac_err(adpt,
					 "error:%d Can not switch on %s pins\n",
					 result,
					 EMAC_PINCTRL_STATE_EPHY_ACTIVE);
			if (!ret)
				ret = result;
		}
	}
	return ret;
}

static inline int msm_emac_request_pinctrl_off(struct emac_adapter *adpt)
static inline int msm_emac_request_pinctrl_off(struct emac_adapter *adpt,
					       bool mdio, bool ephy)
{
	int result = 0;
	int ret    = 0;
	struct emac_phy *phy = &adpt->phy;

	result = pinctrl_select_state(adpt->pinctrl, adpt->pins_sleep);
	if (phy->external) {
		if (mdio) {
			result = pinctrl_select_state(adpt->pinctrl,
						      adpt->mdio_pins_sleep);
			if (result)
		emac_err(adpt, "error:%d Can not set %s pins\n",
			 result, EMAC_PINCTRL_STATE_SLEEP);
	return result;
				emac_err(adpt,
					 "error:%d Can not switch off %s pins\n",
					 result, EMAC_PINCTRL_STATE_MDIO_SLEEP);
			ret = result;
		}

		if (ephy) {
			result = pinctrl_select_state(adpt->pinctrl,
						      adpt->ephy_pins_sleep);
			if (result)
				emac_err(adpt,
					 "error:%d Can not switch off %s pins\n",
					 result, EMAC_PINCTRL_STATE_EPHY_SLEEP);
			if (!ret)
				ret = result;
		}
	}
	return ret;
}

/* Bringup the interface/HW */
@@ -1946,10 +2000,6 @@ int emac_up(struct emac_adapter *adpt)
	if (retval)
		return retval;

	retval = adpt->gpio_on(adpt);
	if (retval < 0)
		goto err_request_gpio;

	for (i = 0; i < EMAC_IRQ_CNT; i++) {
		struct emac_irq_per_dev *irq = &adpt->irq[i];
		const struct emac_irq_common *irq_cmn = &emac_irq_cmn_tbl[i];
@@ -1989,8 +2039,6 @@ int emac_up(struct emac_adapter *adpt)
	return retval;

err_request_irq:
	adpt->gpio_off(adpt);
err_request_gpio:
	adpt->phy.ops.down(adpt);
	return retval;
}
@@ -2018,8 +2066,6 @@ void emac_down(struct emac_adapter *adpt, u32 ctrl)
		if (adpt->irq[i].irq)
			free_irq(adpt->irq[i].irq, &adpt->irq[i]);

	adpt->gpio_off(adpt);

	CLR_FLAG(adpt, ADPT_TASK_LSC_REQ);
	CLR_FLAG(adpt, ADPT_TASK_REINIT_REQ);
	CLR_FLAG(adpt, ADPT_TASK_CHK_SGMII_REQ);
@@ -2718,20 +2764,36 @@ static int msm_emac_pinctrl_init(struct emac_adapter *adpt, struct device *dev)
			 PTR_ERR(adpt->pinctrl));
		return PTR_ERR(adpt->pinctrl);
	}
	adpt->pins_active = pinctrl_lookup_state(adpt->pinctrl,
				EMAC_PINCTRL_STATE_ACTIVE);
	if (IS_ERR_OR_NULL(adpt->pins_active)) {
		emac_dbg(adpt, probe, "error:%ld Failed to lookup pinctrl active state\n",
			 PTR_ERR(adpt->pins_active));
		return PTR_ERR(adpt->pins_active);
	adpt->mdio_pins_active = pinctrl_lookup_state(adpt->pinctrl,
				EMAC_PINCTRL_STATE_MDIO_ACTIVE);
	if (IS_ERR_OR_NULL(adpt->mdio_pins_active)) {
		emac_dbg(adpt, probe, "error:%ld Failed to lookup mdio pinctrl active state\n",
			 PTR_ERR(adpt->mdio_pins_active));
		return PTR_ERR(adpt->mdio_pins_active);
	}

	adpt->mdio_pins_sleep = pinctrl_lookup_state(adpt->pinctrl,
				EMAC_PINCTRL_STATE_MDIO_SLEEP);
	if (IS_ERR_OR_NULL(adpt->mdio_pins_sleep)) {
		emac_dbg(adpt, probe, "error:%ld Failed to lookup mdio pinctrl sleep state\n",
			 PTR_ERR(adpt->mdio_pins_sleep));
		return PTR_ERR(adpt->mdio_pins_sleep);
	}

	adpt->ephy_pins_active = pinctrl_lookup_state(adpt->pinctrl,
				EMAC_PINCTRL_STATE_EPHY_ACTIVE);
	if (IS_ERR_OR_NULL(adpt->ephy_pins_active)) {
		emac_dbg(adpt, probe, "error:%ld Failed to lookup ephy pinctrl active state\n",
			 PTR_ERR(adpt->ephy_pins_active));
		return PTR_ERR(adpt->ephy_pins_active);
	}

	adpt->pins_sleep = pinctrl_lookup_state(adpt->pinctrl,
				EMAC_PINCTRL_STATE_SLEEP);
	if (IS_ERR_OR_NULL(adpt->pins_sleep)) {
		emac_dbg(adpt, probe, "error:%ld Failed to lookup pinctrl sleep state\n",
			 PTR_ERR(adpt->pins_sleep));
		return PTR_ERR(adpt->pins_sleep);
	adpt->ephy_pins_sleep = pinctrl_lookup_state(adpt->pinctrl,
				EMAC_PINCTRL_STATE_EPHY_SLEEP);
	if (IS_ERR_OR_NULL(adpt->ephy_pins_sleep)) {
		emac_dbg(adpt, probe, "error:%ld Failed to lookup ephy pinctrl sleep state\n",
			 PTR_ERR(adpt->ephy_pins_sleep));
		return PTR_ERR(adpt->ephy_pins_sleep);
	}

	return 0;
@@ -3116,6 +3178,8 @@ static int emac_suspend(struct device *device)
	emac_hw_config_pow_save(hw, phy->link_speed, !!wufc,
				!!(wufc & EMAC_WOL_MAGIC));

	/* Don't reset ephy as need it for WOL/Link detection later */
	adpt->gpio_off(adpt, true, false);
	emac_disable_clks(adpt);
	emac_disable_regulator(adpt);
	return 0;
@@ -3130,11 +3194,13 @@ static int emac_resume(struct device *device)
	struct emac_hw  *hw  = &adpt->hw;
	u32 retval;

	adpt->gpio_on(adpt, true, false);
	emac_enable_regulator(adpt);
	emac_init_clks(adpt);
	emac_enable_clks(adpt);

	emac_hw_reset_mac(hw);
	emac_phy_reset_external(adpt);
	retval = emac_phy_setup_link(adpt, phy->autoneg_advertised, true,
				     !phy->disable_fc_autoneg);
	if (retval)
@@ -3244,6 +3310,11 @@ static int emac_probe(struct platform_device *pdev)
	if (retval)
		goto err_clk_en;

	/* Configure MDIO lines */
	retval = adpt->gpio_on(adpt, true, true);
	if (retval)
		goto err_init_mdio_gpio;

	/* init external phy */
	retval = emac_phy_init_external(adpt);
	if (retval)
@@ -3313,6 +3384,8 @@ static int emac_probe(struct platform_device *pdev)
err_register_netdev:
err_phy_link:
err_init_ephy:
	adpt->gpio_off(adpt, true, true);
err_init_mdio_gpio:
err_clk_en:
err_init_phy:
err_clk_init:
@@ -3339,6 +3412,7 @@ static int emac_remove(struct platform_device *pdev)
	if (TEST_FLAG(hw, HW_PTP_CAP))
		emac_ptp_remove(netdev);

	adpt->gpio_off(adpt, true, true);
	emac_disable_regulator(adpt);
	emac_disable_clks(adpt);
	emac_release_resources(adpt);
+16 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -217,6 +217,19 @@ int emac_phy_write(struct emac_adapter *adpt, u16 phy_addr, u16 reg_addr,
	return retval;
}

/* reset external phy */
void emac_phy_reset_external(struct emac_adapter *adpt)
{
	/* Trigger ephy reset by pulling line low */
	adpt->gpio_off(adpt, false, true);
	/* need delay to complete ephy reset */
	usleep_range(10000, 20000);
	/* Complete ephy reset by pulling line back up */
	adpt->gpio_on(adpt, false, true);
	/* need delay to complete ephy reset */
	usleep_range(10000, 20000);
}

/* initialize external phy */
int emac_phy_init_external(struct emac_adapter *adpt)
{
@@ -226,6 +239,8 @@ int emac_phy_init_external(struct emac_adapter *adpt)
	int retval = 0;

	if (phy->external) {
		emac_phy_reset_external(adpt);

		retval = emac_phy_read(adpt, phy->addr, MII_PHYSID1,
				       &phy_id[0]);
		if (retval)
Loading