/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2001-2020 Intel Corporation
 */

/*
 * 82542 Gigabit Ethernet Controller
 */

#include "e1000_api.h"

STATIC s32  e1000_init_phy_params_82542(struct e1000_hw *hw);
STATIC s32  e1000_init_nvm_params_82542(struct e1000_hw *hw);
STATIC s32  e1000_init_mac_params_82542(struct e1000_hw *hw);
STATIC s32  e1000_get_bus_info_82542(struct e1000_hw *hw);
STATIC s32  e1000_reset_hw_82542(struct e1000_hw *hw);
STATIC s32  e1000_init_hw_82542(struct e1000_hw *hw);
STATIC s32  e1000_setup_link_82542(struct e1000_hw *hw);
STATIC s32  e1000_led_on_82542(struct e1000_hw *hw);
STATIC s32  e1000_led_off_82542(struct e1000_hw *hw);
STATIC int  e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index);
STATIC void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw);
STATIC s32  e1000_read_mac_addr_82542(struct e1000_hw *hw);

/**
 *  e1000_init_phy_params_82542 - Init PHY func ptrs.
 *  @hw: pointer to the HW structure
 **/
STATIC s32 e1000_init_phy_params_82542(struct e1000_hw *hw)
{
	struct e1000_phy_info *phy = &hw->phy;
	s32 ret_val = E1000_SUCCESS;

	DEBUGFUNC("e1000_init_phy_params_82542");

	phy->type = e1000_phy_none;

	return ret_val;
}

/**
 *  e1000_init_nvm_params_82542 - Init NVM func ptrs.
 *  @hw: pointer to the HW structure
 **/
STATIC s32 e1000_init_nvm_params_82542(struct e1000_hw *hw)
{
	struct e1000_nvm_info *nvm = &hw->nvm;

	DEBUGFUNC("e1000_init_nvm_params_82542");

	nvm->address_bits	=  6;
	nvm->delay_usec		= 50;
	nvm->opcode_bits	=  3;
	nvm->type		= e1000_nvm_eeprom_microwire;
	nvm->word_size		= 64;

	/* Function Pointers */
	nvm->ops.read		= e1000_read_nvm_microwire;
	nvm->ops.release	= e1000_stop_nvm;
	nvm->ops.write		= e1000_write_nvm_microwire;
	nvm->ops.update		= e1000_update_nvm_checksum_generic;
	nvm->ops.validate	= e1000_validate_nvm_checksum_generic;

	return E1000_SUCCESS;
}

/**
 *  e1000_init_mac_params_82542 - Init MAC func ptrs.
 *  @hw: pointer to the HW structure
 **/
STATIC s32 e1000_init_mac_params_82542(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;

	DEBUGFUNC("e1000_init_mac_params_82542");

	/* Set media type */
	hw->phy.media_type = e1000_media_type_fiber;

	/* Set mta register count */
	mac->mta_reg_count = 128;
	/* Set rar entry count */
	mac->rar_entry_count = E1000_RAR_ENTRIES;

	/* Function pointers */

	/* bus type/speed/width */
	mac->ops.get_bus_info = e1000_get_bus_info_82542;
	/* function id */
	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
	/* reset */
	mac->ops.reset_hw = e1000_reset_hw_82542;
	/* hw initialization */
	mac->ops.init_hw = e1000_init_hw_82542;
	/* link setup */
	mac->ops.setup_link = e1000_setup_link_82542;
	/* phy/fiber/serdes setup */
	mac->ops.setup_physical_interface =
					e1000_setup_fiber_serdes_link_generic;
	/* check for link */
	mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
	/* multicast address update */
	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
	/* writing VFTA */
	mac->ops.write_vfta = e1000_write_vfta_generic;
	/* clearing VFTA */
	mac->ops.clear_vfta = e1000_clear_vfta_generic;
	/* read mac address */
	mac->ops.read_mac_addr = e1000_read_mac_addr_82542;
	/* set RAR */
	mac->ops.rar_set = e1000_rar_set_82542;
	/* turn on/off LED */
	mac->ops.led_on = e1000_led_on_82542;
	mac->ops.led_off = e1000_led_off_82542;
	/* clear hardware counters */
	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82542;
	/* link info */
	mac->ops.get_link_up_info =
				e1000_get_speed_and_duplex_fiber_serdes_generic;

	return E1000_SUCCESS;
}

/**
 *  e1000_init_function_pointers_82542 - Init func ptrs.
 *  @hw: pointer to the HW structure
 *
 *  Called to initialize all function pointers and parameters.
 **/
void e1000_init_function_pointers_82542(struct e1000_hw *hw)
{
	DEBUGFUNC("e1000_init_function_pointers_82542");

	hw->mac.ops.init_params = e1000_init_mac_params_82542;
	hw->nvm.ops.init_params = e1000_init_nvm_params_82542;
	hw->phy.ops.init_params = e1000_init_phy_params_82542;
}

/**
 *  e1000_get_bus_info_82542 - Obtain bus information for adapter
 *  @hw: pointer to the HW structure
 *
 *  This will obtain information about the HW bus for which the
 *  adapter is attached and stores it in the hw structure.
 **/
STATIC s32 e1000_get_bus_info_82542(struct e1000_hw *hw)
{
	DEBUGFUNC("e1000_get_bus_info_82542");

	hw->bus.type = e1000_bus_type_pci;
	hw->bus.speed = e1000_bus_speed_unknown;
	hw->bus.width = e1000_bus_width_unknown;

	return E1000_SUCCESS;
}

/**
 *  e1000_reset_hw_82542 - Reset hardware
 *  @hw: pointer to the HW structure
 *
 *  This resets the hardware into a known state.
 **/
STATIC s32 e1000_reset_hw_82542(struct e1000_hw *hw)
{
	struct e1000_bus_info *bus = &hw->bus;
	s32 ret_val = E1000_SUCCESS;
	u32 ctrl;

	DEBUGFUNC("e1000_reset_hw_82542");

	if (hw->revision_id == E1000_REVISION_2) {
		DEBUGOUT("Disabling MWI on 82542 rev 2\n");
		e1000_pci_clear_mwi(hw);
	}

	DEBUGOUT("Masking off all interrupts\n");
	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);

	E1000_WRITE_REG(hw, E1000_RCTL, 0);
	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
	E1000_WRITE_FLUSH(hw);

	/*
	 * Delay to allow any outstanding PCI transactions to complete before
	 * resetting the device
	 */
	msec_delay(10);

	ctrl = E1000_READ_REG(hw, E1000_CTRL);

	DEBUGOUT("Issuing a global reset to 82542/82543 MAC\n");
	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);

	hw->nvm.ops.reload(hw);
	msec_delay(2);

	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
	E1000_READ_REG(hw, E1000_ICR);

	if (hw->revision_id == E1000_REVISION_2) {
		if (bus->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
			e1000_pci_set_mwi(hw);
	}

	return ret_val;
}

/**
 *  e1000_init_hw_82542 - Initialize hardware
 *  @hw: pointer to the HW structure
 *
 *  This inits the hardware readying it for operation.
 **/
STATIC s32 e1000_init_hw_82542(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;
	struct e1000_dev_spec_82542 *dev_spec = &hw->dev_spec._82542;
	s32 ret_val = E1000_SUCCESS;
	u32 ctrl;
	u16 i;

	DEBUGFUNC("e1000_init_hw_82542");

	/* Disabling VLAN filtering */
	E1000_WRITE_REG(hw, E1000_VET, 0);
	mac->ops.clear_vfta(hw);

	/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
	if (hw->revision_id == E1000_REVISION_2) {
		DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
		e1000_pci_clear_mwi(hw);
		E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST);
		E1000_WRITE_FLUSH(hw);
		msec_delay(5);
	}

	/* Setup the receive address. */
	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);

	/* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
	if (hw->revision_id == E1000_REVISION_2) {
		E1000_WRITE_REG(hw, E1000_RCTL, 0);
		E1000_WRITE_FLUSH(hw);
		msec_delay(1);
		if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
			e1000_pci_set_mwi(hw);
	}

	/* Zero out the Multicast HASH table */
	DEBUGOUT("Zeroing the MTA\n");
	for (i = 0; i < mac->mta_reg_count; i++)
		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);

	/*
	 * Set the PCI priority bit correctly in the CTRL register.  This
	 * determines if the adapter gives priority to receives, or if it
	 * gives equal priority to transmits and receives.
	 */
	if (dev_spec->dma_fairness) {
		ctrl = E1000_READ_REG(hw, E1000_CTRL);
		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR);
	}

	/* Setup link and flow control */
	ret_val = e1000_setup_link_82542(hw);

	/*
	 * Clear all of the statistics registers (clear on read).  It is
	 * important that we do this after we have tried to establish link
	 * because the symbol error count will increment wildly if there
	 * is no link.
	 */
	e1000_clear_hw_cntrs_82542(hw);

	return ret_val;
}

/**
 *  e1000_setup_link_82542 - Setup flow control and link settings
 *  @hw: pointer to the HW structure
 *
 *  Determines which flow control settings to use, then configures flow
 *  control.  Calls the appropriate media-specific link configuration
 *  function.  Assuming the adapter has a valid link partner, a valid link
 *  should be established.  Assumes the hardware has previously been reset
 *  and the transmitter and receiver are not enabled.
 **/
STATIC s32 e1000_setup_link_82542(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;
	s32 ret_val;

	DEBUGFUNC("e1000_setup_link_82542");

	ret_val = e1000_set_default_fc_generic(hw);
	if (ret_val)
		goto out;

	hw->fc.requested_mode &= ~e1000_fc_tx_pause;

	if (mac->report_tx_early)
		hw->fc.requested_mode &= ~e1000_fc_rx_pause;

	/*
	 * Save off the requested flow control mode for use later.  Depending
	 * on the link partner's capabilities, we may or may not use this mode.
	 */
	hw->fc.current_mode = hw->fc.requested_mode;

	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
		  hw->fc.current_mode);

	/* Call the necessary subroutine to configure the link. */
	ret_val = mac->ops.setup_physical_interface(hw);
	if (ret_val)
		goto out;

	/*
	 * Initialize the flow control address, type, and PAUSE timer
	 * registers to their default values.  This is done even if flow
	 * control is disabled, because it does not hurt anything to
	 * initialize these registers.
	 */
	DEBUGOUT("Initializing Flow Control address, type and timer regs\n");

	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);

	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);

	ret_val = e1000_set_fc_watermarks_generic(hw);

out:
	return ret_val;
}

/**
 *  e1000_led_on_82542 - Turn on SW controllable LED
 *  @hw: pointer to the HW structure
 *
 *  Turns the SW defined LED on.
 **/
STATIC s32 e1000_led_on_82542(struct e1000_hw *hw)
{
	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);

	DEBUGFUNC("e1000_led_on_82542");

	ctrl |= E1000_CTRL_SWDPIN0;
	ctrl |= E1000_CTRL_SWDPIO0;
	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);

	return E1000_SUCCESS;
}

/**
 *  e1000_led_off_82542 - Turn off SW controllable LED
 *  @hw: pointer to the HW structure
 *
 *  Turns the SW defined LED off.
 **/
STATIC s32 e1000_led_off_82542(struct e1000_hw *hw)
{
	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);

	DEBUGFUNC("e1000_led_off_82542");

	ctrl &= ~E1000_CTRL_SWDPIN0;
	ctrl |= E1000_CTRL_SWDPIO0;
	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);

	return E1000_SUCCESS;
}

/**
 *  e1000_rar_set_82542 - Set receive address register
 *  @hw: pointer to the HW structure
 *  @addr: pointer to the receive address
 *  @index: receive address array register
 *
 *  Sets the receive address array register at index to the address passed
 *  in by addr.
 **/
STATIC int e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index)
{
	u32 rar_low, rar_high;

	DEBUGFUNC("e1000_rar_set_82542");

	/*
	 * HW expects these in little endian so we reverse the byte order
	 * from network order (big endian) to little endian
	 */
	rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
		   ((u32) addr[2] << 16) | ((u32) addr[3] << 24));

	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));

	/* If MAC address zero, no need to set the AV bit */
	if (rar_low || rar_high)
		rar_high |= E1000_RAH_AV;

	E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
	E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);

	return E1000_SUCCESS;
}

/**
 *  e1000_translate_register_82542 - Translate the proper register offset
 *  @reg: e1000 register to be read
 *
 *  Registers in 82542 are located in different offsets than other adapters
 *  even though they function in the same manner.  This function takes in
 *  the name of the register to read and returns the correct offset for
 *  82542 silicon.
 **/
u32 e1000_translate_register_82542(u32 reg)
{
	/*
	 * Some of the 82542 registers are located at different
	 * offsets than they are in newer adapters.
	 * Despite the difference in location, the registers
	 * function in the same manner.
	 */
	switch (reg) {
	case E1000_RA:
		reg = 0x00040;
		break;
	case E1000_RDTR:
		reg = 0x00108;
		break;
	case E1000_RDBAL(0):
		reg = 0x00110;
		break;
	case E1000_RDBAH(0):
		reg = 0x00114;
		break;
	case E1000_RDLEN(0):
		reg = 0x00118;
		break;
	case E1000_RDH(0):
		reg = 0x00120;
		break;
	case E1000_RDT(0):
		reg = 0x00128;
		break;
	case E1000_RDBAL(1):
		reg = 0x00138;
		break;
	case E1000_RDBAH(1):
		reg = 0x0013C;
		break;
	case E1000_RDLEN(1):
		reg = 0x00140;
		break;
	case E1000_RDH(1):
		reg = 0x00148;
		break;
	case E1000_RDT(1):
		reg = 0x00150;
		break;
	case E1000_FCRTH:
		reg = 0x00160;
		break;
	case E1000_FCRTL:
		reg = 0x00168;
		break;
	case E1000_MTA:
		reg = 0x00200;
		break;
	case E1000_TDBAL(0):
		reg = 0x00420;
		break;
	case E1000_TDBAH(0):
		reg = 0x00424;
		break;
	case E1000_TDLEN(0):
		reg = 0x00428;
		break;
	case E1000_TDH(0):
		reg = 0x00430;
		break;
	case E1000_TDT(0):
		reg = 0x00438;
		break;
	case E1000_TIDV:
		reg = 0x00440;
		break;
	case E1000_VFTA:
		reg = 0x00600;
		break;
	case E1000_TDFH:
		reg = 0x08010;
		break;
	case E1000_TDFT:
		reg = 0x08018;
		break;
	default:
		break;
	}

	return reg;
}

/**
 *  e1000_clear_hw_cntrs_82542 - Clear device specific hardware counters
 *  @hw: pointer to the HW structure
 *
 *  Clears the hardware counters by reading the counter registers.
 **/
STATIC void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw)
{
	DEBUGFUNC("e1000_clear_hw_cntrs_82542");

	e1000_clear_hw_cntrs_base_generic(hw);

	E1000_READ_REG(hw, E1000_PRC64);
	E1000_READ_REG(hw, E1000_PRC127);
	E1000_READ_REG(hw, E1000_PRC255);
	E1000_READ_REG(hw, E1000_PRC511);
	E1000_READ_REG(hw, E1000_PRC1023);
	E1000_READ_REG(hw, E1000_PRC1522);
	E1000_READ_REG(hw, E1000_PTC64);
	E1000_READ_REG(hw, E1000_PTC127);
	E1000_READ_REG(hw, E1000_PTC255);
	E1000_READ_REG(hw, E1000_PTC511);
	E1000_READ_REG(hw, E1000_PTC1023);
	E1000_READ_REG(hw, E1000_PTC1522);
}

/**
 *  e1000_read_mac_addr_82542 - Read device MAC address
 *  @hw: pointer to the HW structure
 *
 *  Reads the device MAC address from the EEPROM and stores the value.
 **/
s32 e1000_read_mac_addr_82542(struct e1000_hw *hw)
{
	s32  ret_val = E1000_SUCCESS;
	u16 offset, nvm_data, i;

	DEBUGFUNC("e1000_read_mac_addr");

	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
		offset = i >> 1;
		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
		if (ret_val) {
			DEBUGOUT("NVM Read Error\n");
			goto out;
		}
		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
	}

	for (i = 0; i < ETH_ADDR_LEN; i++)
		hw->mac.addr[i] = hw->mac.perm_addr[i];

out:
	return ret_val;
}