/*******************************************************************************
* mvEthSpeedDuplexSet -
*
* DESCRIPTION:
*       Sets port speed to Auto Negotiation / 1000 / 100 / 10 Mbps.
*	Sets port duplex to Auto Negotiation / Full / Half Duplex.
*
* INPUT:
* 	int portNo - port number
* 	MV_ETH_PORT_SPEED speed - port speed
*	MV_ETH_PORT_DUPLEX duplex - port duplex mode
*
* RETURN:
*******************************************************************************/
MV_STATUS mvEthSpeedDuplexSet(int portNo, MV_ETH_PORT_SPEED speed, MV_ETH_PORT_DUPLEX duplex)
{
	MV_U32 regVal;

	/* Check validity */
	if ((speed == MV_ETH_SPEED_1000) && (duplex == MV_ETH_DUPLEX_HALF))
		return MV_BAD_PARAM;

	regVal = MV_REG_READ(ETH_GMAC_AN_CTRL_REG(portNo));

	switch (speed) {
	case MV_ETH_SPEED_AN:
		regVal |= ETH_ENABLE_SPEED_AUTO_NEG_MASK;
		/* the other bits don't matter in this case */
		break;
	case MV_ETH_SPEED_1000:
		regVal &= ~ETH_ENABLE_SPEED_AUTO_NEG_MASK;
		regVal |= ETH_SET_GMII_SPEED_1000_MASK;
		regVal &= ~ETH_SET_MII_SPEED_100_MASK;
		/* the 100/10 bit doesn't matter in this case */
		break;
	case MV_ETH_SPEED_100:
		regVal &= ~ETH_ENABLE_SPEED_AUTO_NEG_MASK;
		regVal &= ~ETH_SET_GMII_SPEED_1000_MASK;
		regVal |= ETH_SET_MII_SPEED_100_MASK;
		break;
	case MV_ETH_SPEED_10:
		regVal &= ~ETH_ENABLE_SPEED_AUTO_NEG_MASK;
		regVal &= ~ETH_SET_GMII_SPEED_1000_MASK;
		regVal &= ~ETH_SET_MII_SPEED_100_MASK;
		break;
	default:
		mvOsPrintf("Unexpected Speed value %d\n", speed);
		return MV_BAD_PARAM;
	}

	switch (duplex) {
	case MV_ETH_DUPLEX_AN:
		regVal  |= ETH_ENABLE_DUPLEX_AUTO_NEG_MASK;
		/* the other bits don't matter in this case */
		break;
	case MV_ETH_DUPLEX_HALF:
		regVal &= ~ETH_ENABLE_DUPLEX_AUTO_NEG_MASK;
		regVal &= ~ETH_SET_FULL_DUPLEX_MASK;
		break;
	case MV_ETH_DUPLEX_FULL:
		regVal &= ~ETH_ENABLE_DUPLEX_AUTO_NEG_MASK;
		regVal |= ETH_SET_FULL_DUPLEX_MASK;
		break;
	default:
		mvOsPrintf("Unexpected Duplex value %d\n", duplex);
		return MV_BAD_PARAM;
	}

	mvPp2WrReg(ETH_GMAC_AN_CTRL_REG(portNo), regVal);
	return MV_OK;
}
/*******************************************************************************
* mvEthSpeedDuplexGet -
*
* DESCRIPTION:
*       Gets port speed
*	Gets port duplex
*
* INPUT:
* 	int portNo - port number
* OUTPUT:
* 	MV_ETH_PORT_SPEED *speed - port speed
*	MV_ETH_PORT_DUPLEX *duplex - port duplex mode
*
* RETURN:
*******************************************************************************/
MV_STATUS mvEthSpeedDuplexGet(int portNo, MV_ETH_PORT_SPEED *speed, MV_ETH_PORT_DUPLEX *duplex)
{
	MV_U32 regVal;

	/* Check validity */
	if (!speed || !duplex)
		return MV_BAD_PARAM;

	regVal = MV_REG_READ(ETH_GMAC_AN_CTRL_REG(portNo));
	if (regVal & ETH_ENABLE_SPEED_AUTO_NEG_MASK)
		*speed = MV_ETH_SPEED_AN;
	else if (regVal & ETH_SET_GMII_SPEED_1000_MASK)
		*speed = MV_ETH_SPEED_1000;
	else if (regVal & ETH_SET_MII_SPEED_100_MASK)
		*speed = MV_ETH_SPEED_100;
	else
		*speed = MV_ETH_SPEED_10;

	if (regVal & ETH_ENABLE_DUPLEX_AUTO_NEG_MASK)
		*duplex = MV_ETH_DUPLEX_AN;
	else if (regVal & ETH_SET_FULL_DUPLEX_MASK)
		*duplex = MV_ETH_DUPLEX_FULL;
	else
		*duplex = MV_ETH_DUPLEX_HALF;

	return MV_OK;
}
/*******************************************************************************
* mvEthFlowCtrlSet - Set Flow Control of the port.
*
* DESCRIPTION:
*       This function configures the port's Flow Control properties.
*
* INPUT:
*       int				port		- Port number
*       MV_ETH_PORT_FC  flowControl - Flow control of the port.
*
* RETURN:   MV_STATUS
*       MV_OK           - Success
*       MV_OUT_OF_RANGE - Failed. Port is out of valid range
*       MV_BAD_VALUE    - Value flowControl parameters is not valid
*
*******************************************************************************/
MV_STATUS mvEthFlowCtrlSet(int port, MV_ETH_PORT_FC flowControl)
{
	MV_U32 regVal;

	regVal = MV_REG_READ(ETH_GMAC_AN_CTRL_REG(port));

	switch (flowControl) {
	case MV_ETH_FC_AN_NO:
		regVal |= ETH_ENABLE_FLOW_CONTROL_AUTO_NEG_MASK;
		regVal &= ~ETH_FLOW_CONTROL_ADVERTISE_MASK;
		regVal &= ~ETH_FLOW_CONTROL_ASYMETRIC_MASK;
		break;

	case MV_ETH_FC_AN_SYM:
		regVal |= ETH_ENABLE_FLOW_CONTROL_AUTO_NEG_MASK;
		regVal |= ETH_FLOW_CONTROL_ADVERTISE_MASK;
		regVal &= ~ETH_FLOW_CONTROL_ASYMETRIC_MASK;
		break;

	case MV_ETH_FC_AN_ASYM:
		regVal |= ETH_ENABLE_FLOW_CONTROL_AUTO_NEG_MASK;
		regVal |= ETH_FLOW_CONTROL_ADVERTISE_MASK;
		regVal |= ETH_FLOW_CONTROL_ASYMETRIC_MASK;
		break;

	case MV_ETH_FC_DISABLE:
		regVal &= ~ETH_ENABLE_FLOW_CONTROL_AUTO_NEG_MASK;
		regVal &= ~ETH_SET_FLOW_CONTROL_MASK;
		break;

	case MV_ETH_FC_ENABLE:
		regVal &= ~ETH_ENABLE_FLOW_CONTROL_AUTO_NEG_MASK;
		regVal |= ETH_SET_FLOW_CONTROL_MASK;
		break;

	default:
		mvOsPrintf("ethDrv: Unexpected FlowControl value %d\n", flowControl);
		return MV_BAD_VALUE;
	}

	mvPp2WrReg(ETH_GMAC_AN_CTRL_REG(port), regVal);

	return MV_OK;
}
static void mvEthComplexPortInBandAnEnable(MV_U32 port, MV_BOOL enable)
{
	MV_U32 reg;
	reg = MV_REG_READ(ETH_GMAC_AN_CTRL_REG(port));

	/* Enable AnBandAnEn */
	reg &= ~MV_ETH_IN_BAND_AN_EN_MASK;
	reg |= (0x1 << MV_ETH_IN_BAND_AN_EN_OFFSET);

	/* Disable AnDuplex, AnSpeedEn, AnFcEn */
	if (enable == MV_FALSE) {
		reg &= ~MV_ETH_SPEED_AUTO_NEG_MASK;
		reg |= (0x0 << MV_ETH_SPEED_AUTO_NEG_OFFSET);
		reg &= ~MV_ETH_FLOW_CTRL_AUTO_NEG_MASK;
		reg |= (0x0 << MV_ETH_FLOW_CTRL_AUTO_NEG_OFFSET);
		reg &= ~MV_ETH_DUPLEX_AUTO_NEG_MASK;
		reg |= (0x0 << MV_ETH_DUPLEX_AUTO_NEG_OFFSET);
	}
	MV_REG_WRITE(ETH_GMAC_AN_CTRL_REG(port), reg);
}
/*******************************************************************************
* mvEthForceLinkModeSet -
*
* DESCRIPTION:
*       Sets "Force Link Pass" and "Do Not Force Link Fail" bits.
* 	Note: This function should only be called when the port is disabled.
*
* INPUT:
* 	int		portNo			- port number
* 	MV_BOOL force_link_pass	- Force Link Pass
* 	MV_BOOL force_link_fail - Force Link Failure
*		0, 0 - normal state: detect link via PHY and connector
*		1, 1 - prohibited state.
*
* RETURN:
*******************************************************************************/
MV_STATUS mvEthForceLinkModeSet(int portNo, MV_BOOL force_link_up, MV_BOOL force_link_down)
{
	MV_U32	regVal;

	/* Can't force link pass and link fail at the same time */
	if ((force_link_up) && (force_link_down))
		return MV_BAD_PARAM;

	regVal = MV_REG_READ(ETH_GMAC_AN_CTRL_REG(portNo));

	if (force_link_up)
		regVal |= ETH_FORCE_LINK_PASS_MASK;
	else
		regVal &= ~ETH_FORCE_LINK_PASS_MASK;

	if (force_link_down)
		regVal |= ETH_FORCE_LINK_FAIL_MASK;
	else
		regVal &= ~ETH_FORCE_LINK_FAIL_MASK;

	mvPp2WrReg(ETH_GMAC_AN_CTRL_REG(portNo), regVal);

    return MV_OK;
}
/*******************************************************************************
* mvEthFlowCtrlGet - Get Flow Control configuration of the port.
*
* DESCRIPTION:
*       This function returns the port's Flow Control properties.
*
* INPUT:
*       int				port		- Port number
*
* OUTPUT:
*       MV_ETH_PORT_FC  *flowCntrl	- Flow control of the port.
*
* RETURN:   MV_STATUS
*       MV_OK           - Success
*       MV_OUT_OF_RANGE - Failed. Port is out of valid range
*
*******************************************************************************/
MV_STATUS mvEthFlowCtrlGet(int port, MV_ETH_PORT_FC *pFlowCntrl)
{
	MV_U32 regVal;

	regVal = MV_REG_READ(ETH_GMAC_AN_CTRL_REG(port));

	if (regVal & ETH_ENABLE_FLOW_CONTROL_AUTO_NEG_MASK) {
		/* Auto negotiation is enabled */
		if (regVal & ETH_FLOW_CONTROL_ADVERTISE_MASK) {
			if (regVal & ETH_FLOW_CONTROL_ASYMETRIC_MASK)
				*pFlowCntrl = MV_ETH_FC_AN_ASYM;
			else
				*pFlowCntrl = MV_ETH_FC_AN_SYM;
		} else
			*pFlowCntrl = MV_ETH_FC_AN_NO;
	} else {
		/* Auto negotiation is disabled */
		if (regVal & ETH_SET_FLOW_CONTROL_MASK)
			*pFlowCntrl = MV_ETH_FC_ENABLE;
		else
			*pFlowCntrl = MV_ETH_FC_DISABLE;
	}
	return MV_OK;
}