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

Commit cb17aab9 authored by Bruce Allan's avatar Bruce Allan Committed by Jeff Kirsher
Browse files

e1000e: PHY initialization flow changes for 82577/8/9



The PHY initialization flows and assorted workarounds for 82577/8/9 done
during driver load and resume from Sx should be the same yet they are not.
Combine the current flows/workarounds into a common set of functions that
are called during the different code paths.

Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 62bc813e
Loading
Loading
Loading
Loading
+146 −101
Original line number Original line Diff line number Diff line
@@ -287,25 +287,126 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
#define ew16flash(reg, val)	__ew16flash(hw, (reg), (val))
#define ew16flash(reg, val)	__ew16flash(hw, (reg), (val))
#define ew32flash(reg, val)	__ew32flash(hw, (reg), (val))
#define ew32flash(reg, val)	__ew32flash(hw, (reg), (val))


static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw)
/**
 *  e1000_phy_is_accessible_pchlan - Check if able to access PHY registers
 *  @hw: pointer to the HW structure
 *
 *  Test access to the PHY registers by reading the PHY ID registers.  If
 *  the PHY ID is already known (e.g. resume path) compare it with known ID,
 *  otherwise assume the read PHY ID is correct if it is valid.
 *
 *  Assumes the sw/fw/hw semaphore is already acquired.
 **/
static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
{
{
	u32 reg;
	u16 phy_reg;
	u32 phy_id;

	hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg);
	phy_id = (u32)(phy_reg << 16);
	hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg);
	phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);

	if (hw->phy.id) {
		if (hw->phy.id == phy_id)
			return true;
	} else {
		if ((phy_id != 0) && (phy_id != PHY_REVISION_MASK))
			hw->phy.id = phy_id;
		return true;
	}

	return false;
}

/**
 *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
 *  @hw: pointer to the HW structure
 *
 *  Workarounds/flow necessary for PHY initialization during driver load
 *  and resume paths.
 **/
static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
{
	u32 mac_reg, fwsm = er32(FWSM);
	s32 ret_val;

	ret_val = hw->phy.ops.acquire(hw);
	if (ret_val) {
		e_dbg("Failed to initialize PHY flow\n");
		return ret_val;
	}

	/*
	 * The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
	 * inaccessible and resetting the PHY is not blocked, toggle the
	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
	 */
	switch (hw->mac.type) {
	case e1000_pch2lan:
		/*
		 * Gate automatic PHY configuration by hardware on
		 * non-managed 82579
		 */
		if (!(fwsm & E1000_ICH_FWSM_FW_VALID))
			e1000_gate_hw_phy_config_ich8lan(hw, true);

		if (e1000_phy_is_accessible_pchlan(hw))
			break;

		/* fall-through */
	case e1000_pchlan:
		if ((hw->mac.type == e1000_pchlan) &&
		    (fwsm & E1000_ICH_FWSM_FW_VALID))
			break;

		if (hw->phy.ops.check_reset_block(hw)) {
			e_dbg("Required LANPHYPC toggle blocked by ME\n");
			break;
		}

		e_dbg("Toggling LANPHYPC\n");


		/* Set Phy Config Counter to 50msec */
		/* Set Phy Config Counter to 50msec */
	reg = er32(FEXTNVM3);
		mac_reg = er32(FEXTNVM3);
	reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
		mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
	reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
		mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
	ew32(FEXTNVM3, reg);
		ew32(FEXTNVM3, mac_reg);


		/* Toggle LANPHYPC Value bit */
		/* Toggle LANPHYPC Value bit */
	reg = er32(CTRL);
		mac_reg = er32(CTRL);
	reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
		mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
	reg &= ~E1000_CTRL_LANPHYPC_VALUE;
		mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
	ew32(CTRL, reg);
		ew32(CTRL, mac_reg);
		e1e_flush();
		e1e_flush();
		udelay(10);
		udelay(10);
	reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
		mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
	ew32(CTRL, reg);
		ew32(CTRL, mac_reg);
		e1e_flush();
		msleep(50);
		break;
	default:
		break;
	}

	hw->phy.ops.release(hw);

	/*
	 * Reset the PHY before any access to it.  Doing so, ensures
	 * that the PHY is in a known good state before we read/write
	 * PHY registers.  The generic reset is sufficient here,
	 * because we haven't determined the PHY type yet.
	 */
	ret_val = e1000e_phy_hw_reset_generic(hw);

	/* Ungate automatic PHY configuration on non-managed 82579 */
	if ((hw->mac.type == e1000_pch2lan) &&
	    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
		usleep_range(10000, 20000);
		e1000_gate_hw_phy_config_ich8lan(hw, false);
	}

	return ret_val;
}
}


/**
/**
@@ -335,44 +436,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;


	if (!hw->phy.ops.check_reset_block(hw)) {
	phy->id = e1000_phy_unknown;
		u32 fwsm = er32(FWSM);

		/*
		 * The MAC-PHY interconnect may still be in SMBus mode after
		 * Sx->S0.  If resetting the PHY is not blocked, toggle the
		 * LANPHYPC Value bit to force the interconnect to PCIe mode.
		 */
		e1000_toggle_lanphypc_value_ich8lan(hw);
		msleep(50);

		/*
		 * Gate automatic PHY configuration by hardware on
		 * non-managed 82579
		 */
		if ((hw->mac.type == e1000_pch2lan) &&
		    !(fwsm & E1000_ICH_FWSM_FW_VALID))
			e1000_gate_hw_phy_config_ich8lan(hw, true);


		/*
	ret_val = e1000_init_phy_workarounds_pchlan(hw);
		 * Reset the PHY before any access to it.  Doing so, ensures
		 * that the PHY is in a known good state before we read/write
		 * PHY registers.  The generic reset is sufficient here,
		 * because we haven't determined the PHY type yet.
		 */
		ret_val = e1000e_phy_hw_reset_generic(hw);
	if (ret_val)
	if (ret_val)
		return ret_val;
		return ret_val;


		/* Ungate automatic PHY configuration on non-managed 82579 */
	if (phy->id == e1000_phy_unknown)
		if ((hw->mac.type == e1000_pch2lan) &&
		    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
			usleep_range(10000, 20000);
			e1000_gate_hw_phy_config_ich8lan(hw, false);
		}
	}

	phy->id = e1000_phy_unknown;
		switch (hw->mac.type) {
		switch (hw->mac.type) {
		default:
		default:
			ret_val = e1000e_get_phy_id(hw);
			ret_val = e1000e_get_phy_id(hw);
@@ -3736,41 +3806,16 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
 **/
 **/
void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
{
{
	u16 phy_id1, phy_id2;
	s32 ret_val;
	s32 ret_val;


	if ((hw->mac.type != e1000_pch2lan) ||
	if (hw->mac.type < e1000_pch2lan)
	    hw->phy.ops.check_reset_block(hw))
		return;
		return;


	ret_val = hw->phy.ops.acquire(hw);
	ret_val = e1000_init_phy_workarounds_pchlan(hw);
	if (ret_val) {
	if (ret_val) {
		e_dbg("Failed to acquire PHY semaphore in resume\n");
		e_dbg("Failed to init PHY flow ret_val=%d\n", ret_val);
		return;
		return;
	}
	}

	/* Test access to the PHY registers by reading the ID regs */
	ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_id1);
	if (ret_val)
		goto release;
	ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_id2);
	if (ret_val)
		goto release;

	if (hw->phy.id == ((u32)(phy_id1 << 16) |
			   (u32)(phy_id2 & PHY_REVISION_MASK)))
		goto release;

	e1000_toggle_lanphypc_value_ich8lan(hw);

	hw->phy.ops.release(hw);
	msleep(50);
	e1000_phy_hw_reset(hw);
	msleep(50);
	return;

release:
	hw->phy.ops.release(hw);
}
}


/**
/**