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

Commit a245be81 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: emac: support SGMII link with auto-neg off"

parents 180c80c3 994f0906
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, 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
@@ -193,6 +193,7 @@ struct emac_hw {
	/* PHY parameter */
	u32             phy_addr;
	u16             phy_id[2];
	bool            autoneg;
	u32             autoneg_advertised;
	u32             link_speed;
	bool            link_up;
@@ -676,5 +677,7 @@ extern void emac_set_ethtool_ops(struct net_device *netdev);
extern void emac_reinit_locked(struct emac_adapter *adpt);
extern void emac_update_hw_stats(struct emac_adapter *adpt);
extern int emac_resize_rings(struct net_device *netdev);
extern int emac_up(struct emac_adapter *adpt);
extern void emac_down(struct emac_adapter *adpt, u32 ctrl);

#endif /* _MSM_EMAC_H_ */
+23 −9
Original line number Diff line number Diff line
@@ -89,13 +89,17 @@ static int emac_get_settings(struct net_device *netdev,
			   SUPPORTED_TP);

	ecmd->advertising = ADVERTISED_TP;
	if (hw->autoneg) {
		ecmd->advertising |= ADVERTISED_Autoneg;
		ecmd->advertising |= hw->autoneg_advertised;
		ecmd->autoneg = AUTONEG_ENABLE;
	} else {
		ecmd->autoneg = AUTONEG_DISABLE;
	}

	ecmd->port = PORT_TP;
	ecmd->phy_address = hw->phy_addr;
	ecmd->transceiver = XCVR_INTERNAL;
	ecmd->autoneg = AUTONEG_ENABLE;

	if (hw->link_up) {
		switch (hw->link_speed) {
@@ -176,18 +180,28 @@ static int emac_set_settings(struct net_device *netdev,
		}
	}

	if (hw->autoneg_advertised == advertised) {
		CLI_ADPT_FLAG(STATE_RESETTING);
		return retval;
	}
	if ((hw->autoneg == autoneg) && (hw->autoneg_advertised == advertised))
		goto done;

	retval = emac_setup_phy_link_speed(hw, advertised, autoneg,
					   !hw->disable_fc_autoneg);
	if (retval) {
		retval = emac_setup_phy_link_speed(hw, old, autoneg,
		emac_setup_phy_link_speed(hw, old, autoneg,
					  !hw->disable_fc_autoneg);
	}

	if (netif_running(adpt->netdev)) {
		/* If there is no EPHY, the EMAC internal PHY may get reset in
		 * emac_setup_phy_link_speed. Reset the MAC to avoid the memory
		 * corruption.
		 */
		if (adpt->no_ephy) {
			emac_down(adpt, EMAC_HW_CTRL_RESET_MAC);
			emac_up(adpt);
		}
	}

done:
	CLI_ADPT_FLAG(STATE_RESETTING);
	return retval;
}
+42 −6
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, 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
@@ -34,6 +34,9 @@
#define SGMII_TX_CLK_RATE	125000000
#define SGMII_CXO_CLK_RATE	19200000

static int emac_hw_sgmii_setup_link(struct emac_hw *hw, u32 speed,
				    bool autoneg, bool fc);

/* REG */
u32 emac_reg_r32(struct emac_hw *hw, u8 base, u32 reg)
{
@@ -280,6 +283,8 @@ int emac_hw_init_sgmii(struct emac_hw *hw)
{
	int i;

	emac_hw_sgmii_setup_link(hw, hw->autoneg_advertised,
				 hw->autoneg, !hw->disable_fc_autoneg);
	/* PCS programming */
	emac_reg_w32(hw, EMAC_SGMII_PHY, EMAC_SGMII_PHY_CDR_CTRL0,
		     SGMII_CDR_MAX_CNT);
@@ -434,6 +439,7 @@ int emac_hw_init_phy(struct emac_hw *hw)
		emac_disable_mdio_autopoll(hw);
	}

	hw->autoneg = true;
	hw->autoneg_advertised = EMAC_LINK_SPEED_DEFAULT;

	if (hw->adpt->phy_mode == PHY_INTERFACE_MODE_SGMII)
@@ -453,6 +459,7 @@ static int emac_hw_sgmii_setup_link(struct emac_hw *hw, u32 speed,
				    bool autoneg, bool fc)
{
	u32 val;
	u32 speed_cfg = 0;

	val = emac_reg_r32(hw, EMAC_SGMII_PHY, EMAC_SGMII_PHY_AUTONEG_CFG2);

@@ -463,9 +470,31 @@ static int emac_hw_sgmii_setup_link(struct emac_hw *hw, u32 speed,
			     EMAC_SGMII_PHY_AUTONEG_CFG2, val);
		wmb();
	} else {
		emac_warn(hw->adpt, hw,
			  "No support to turn off SGMII-autoneg\n");
		return -ENOTSUPP;
		switch (speed) {
		case EMAC_LINK_SPEED_10_HALF:
			speed_cfg = SPDMODE_10;
			break;
		case EMAC_LINK_SPEED_10_FULL:
			speed_cfg = SPDMODE_10 | DUPLEX_MODE;
			break;
		case EMAC_LINK_SPEED_100_HALF:
			speed_cfg = SPDMODE_100;
			break;
		case EMAC_LINK_SPEED_100_FULL:
			speed_cfg = SPDMODE_100 | DUPLEX_MODE;
			break;
		case EMAC_LINK_SPEED_1GB_FULL:
			speed_cfg = SPDMODE_1000 | DUPLEX_MODE;
			break;
		default:
			return -EINVAL;
		}
		val &= ~AN_ENABLE;
		emac_reg_w32(hw, EMAC_SGMII_PHY,
			     EMAC_SGMII_PHY_SPEED_CFG1, speed_cfg);
		emac_reg_w32(hw, EMAC_SGMII_PHY,
			     EMAC_SGMII_PHY_AUTONEG_CFG2, val);
		wmb();
	}

	return 0;
@@ -535,7 +564,12 @@ int emac_setup_phy_link(struct emac_hw *hw, u32 speed, bool autoneg, bool fc)

	if (hw->adpt->no_ephy == true) {
		if (hw->adpt->phy_mode == PHY_INTERFACE_MODE_SGMII) {
			return emac_hw_sgmii_setup_link(hw, speed, autoneg, fc);
			hw->autoneg = autoneg;
			hw->autoneg_advertised = speed;
			/* The AN_ENABLE and SPEED_CFG can't change on fly.
			   The SGMII_PHY has to be re-initialized.
			 */
			return emac_hw_reset_sgmii(hw);
		} else {
			emac_err(hw->adpt,
				 "can't setup phy link without ephy\n");
@@ -546,6 +580,8 @@ int emac_setup_phy_link(struct emac_hw *hw, u32 speed, bool autoneg, bool fc)
	if (emac_hw_setup_phy_link(hw, speed, autoneg, fc)) {
		emac_err(hw->adpt, "error when init phy speed and fc\n");
		retval = -EINVAL;
	} else {
		hw->autoneg = autoneg;
	}

	return retval;
@@ -554,7 +590,7 @@ int emac_setup_phy_link(struct emac_hw *hw, u32 speed, bool autoneg, bool fc)
int emac_setup_phy_link_speed(struct emac_hw *hw, u32 speed,
			      bool autoneg, bool fc)
{
	/* update autoneg_advertised based on input link speed */
	/* update speed based on input link speed */
	hw->autoneg_advertised = speed & EMAC_LINK_SPEED_DEFAULT;
	return emac_setup_phy_link(hw, hw->autoneg_advertised, autoneg, fc);
}
+2 −4
Original line number Diff line number Diff line
@@ -59,8 +59,6 @@ static int msm_emac_intr_ext;
module_param_named(intr_ext, msm_emac_intr_ext, int,
		   S_IRUGO | S_IWUSR | S_IWGRP);

static int emac_up(struct emac_adapter *adpt);
static void emac_down(struct emac_adapter *adpt, u32 ctrl);
static irqreturn_t emac_interrupt(int irq, void *data);
static irqreturn_t emac_sgmii_interrupt(int irq, void *data);
static irqreturn_t emac_wol_interrupt(int irq, void *data);
@@ -1451,7 +1449,7 @@ static int emac_change_mtu(struct net_device *netdev, int new_mtu)
}

/* Bringup the interface/HW */
static int emac_up(struct emac_adapter *adpt)
int emac_up(struct emac_adapter *adpt)
{
	struct emac_hw *hw = &adpt->hw;
	struct net_device *netdev = adpt->netdev;
@@ -1520,7 +1518,7 @@ err_request_gpio:
}

/* Bring down the interface/HW */
static void emac_down(struct emac_adapter *adpt, u32 ctrl)
void emac_down(struct emac_adapter *adpt, u32 ctrl)
{
	struct net_device *netdev = adpt->netdev;
	struct emac_hw *hw = &adpt->hw;