#include <config.h>
#include <common.h>

#include "rtl-eth.h"
#include "rtl-vlan.h"

#define    RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__)    (((__portmask__).bits[0] & (0x00000001 << __port__)) ? 1 : 0)
#define    RTK_PORTMASK_SCAN(__portmask__, __port__)           for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++)  if(RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__))
#define    RTK_PORTMASK_CLEAR(__portmask__)                    ((__portmask__).bits[0] = 0)
#define    RTK_PORTMASK_PORT_SET(__portmask__, __port__)       ((__portmask__).bits[0] |= (0x00000001 << __port__))

rtk_uint32 l2p_port[RTK_SWITCH_PORT_NUM] =
	{0, 1, 2, 3, 4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

    /* Physical to Logical */
rtk_uint32 p2l_port[RTK_SWITCH_PORT_NUM] =
	{UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1,
     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT};

    /* Port Type */
rtk_uint32 log_port_type[RTK_SWITCH_PORT_NUM] =
	{UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
     EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT};

    /* PTP port */
rtk_uint32 ptp_port[RTK_SWITCH_PORT_NUM] =
	{1, 1, 1, 1, 1, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0 };

rtk_uint32 valid_portmask =	 ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) );


ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue)
{
	/* Write address control code to register 31 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);

	/* Write address to register 23 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_ADDRESS_REG, reg);

	/* Write read control code to register 21 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP);

	/* Read data from register 25 */
	mii_mgr_read(MDC_MDIO_DUMMY_ID, MDC_MDIO_DATA_READ_REG, pValue);

	return 0;
}

ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value)
{
	/* Write address control code to register 31 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);

	/* Write address to register 23 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_ADDRESS_REG, reg);

	/* Write data to register 24 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_DATA_WRITE_REG, value);

	/* Write data control code to register 21 */
	mii_mgr_write(MDC_MDIO_DUMMY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP);

	return RT_ERR_OK;
}

ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value)
{

	rtk_uint32 regData;
	ret_t retVal;

	if (bit >= RTL8367C_REGBITLENGTH)
		return RT_ERR_INPUT;

	retVal = rtl8367c_getAsicReg(reg, &regData);
	if (retVal != RT_ERR_OK)
		return RT_ERR_SMI;

	if (value)
		regData = regData | (1 << bit);
	else
		regData = regData & (~(1 << bit));

	retVal = rtl8367c_setAsicReg(reg, regData);
	if (retVal != RT_ERR_OK)
		return RT_ERR_SMI;

	return RT_ERR_OK;
}

ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue)
{
	rtk_uint32 regData;

	rtl8367c_getAsicReg(reg, &regData);

	*pValue = (regData & (0x1 << bit)) >> bit;

	return RT_ERR_OK;
}

ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value)
{
	rtk_uint32 regData;
	ret_t retVal;
	rtk_uint32 bitsShift;
	rtk_uint32 valueShifted;

	if (bits >= (1 << RTL8367C_REGBITLENGTH))
		return RT_ERR_INPUT;

	bitsShift = 0;
	while (!(bits & (1 << bitsShift))) {
		bitsShift++;
		if (bitsShift >= RTL8367C_REGBITLENGTH)
			return RT_ERR_INPUT;
	}
	valueShifted = value << bitsShift;

	if (valueShifted > RTL8367C_REGDATAMAX)
		return RT_ERR_INPUT;

	retVal = rtl8367c_getAsicReg(reg, &regData);
	if (retVal != RT_ERR_OK)
		return RT_ERR_SMI;

	regData = regData & (~bits);
	regData = regData | (valueShifted & bits);

	retVal = rtl8367c_setAsicReg(reg, regData);
	if (retVal != RT_ERR_OK)
		return RT_ERR_SMI;

	return RT_ERR_OK;
}

ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue)
{
	rtk_uint32 regData;
	ret_t retVal;
	rtk_uint32 bitsShift;

	if (bits >= (1 << RTL8367C_REGBITLENGTH))
		return RT_ERR_INPUT;

	bitsShift = 0;
	while (!(bits & (1 << bitsShift))) {
		bitsShift++;
		if (bitsShift >= RTL8367C_REGBITLENGTH)
			return RT_ERR_INPUT;
	}

	retVal = rtl8367c_getAsicReg(reg, &regData);
	if (retVal != RT_ERR_OK)
		return RT_ERR_SMI;

	*pValue = (regData & bits) >> bitsShift;

	return RT_ERR_OK;
}

ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData )
{
	ret_t retVal;
	rtk_uint32 regAddr;
	rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1;

	/* OCP prefix */
	ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10);
	retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK,
	                                 ocpAddrPrefix);
	if (retVal != RT_ERR_OK)
		return retVal;

	/*prepare access address*/
	ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F);
	ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F);
	regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1;
	if ((retVal = rtl8367c_setAsicReg(regAddr, ocpData)) != RT_ERR_OK)
		return retVal;

	return RT_ERR_OK;
}

ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData )
{
	ret_t retVal;
	rtk_uint32 regAddr;
	rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1;

	/* OCP prefix */
	ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10);
	retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK,
	                                 ocpAddrPrefix);
	if (retVal != RT_ERR_OK)
		return retVal;

	/*prepare access address*/
	ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F);
	ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F);
	regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1;
	if ((retVal = rtl8367c_getAsicReg(regAddr, pRegData)) != RT_ERR_OK)
		return retVal;

	return RT_ERR_OK;
}

ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 phyData )
{
	rtk_uint32 ocp_addr;
	ocp_addr = 0xa400 + phyAddr << 1;
	return rtl8367c_setAsicPHYOCPReg(phyNo, ocp_addr, phyData);
}

ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 *pRegData )
{
	rtk_uint32 ocp_addr;
	ocp_addr = 0xa400 + phyAddr << 1;
	return rtl8367c_getAsicPHYOCPReg(phyNo, ocp_addr, pRegData);
}
ret_t rtk_switch_init_8367c(void)
{
	rtk_port_t port;
    rtk_uint32 retVal;
    rtk_uint32 regData;
    rtk_uint32 regValue;

    if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK)
        return retVal;

    if( (retVal = rtl8367c_getAsicReg(0x1301, &regValue)) != RT_ERR_OK)
        return retVal;

    if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK)
        return retVal;

	for (port = 0; port < RTK_SWITCH_PORT_NUM; port++)
		if (l2p_port[port] != 0xFF && log_port_type[port] == UTP_PORT)
        {
             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET, 1)) != RT_ERR_OK)
                 return retVal;

             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET, 1)) != RT_ERR_OK)
                 return retVal;

             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET, 1)) != RT_ERR_OK)
                 return retVal;

             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET, 1)) != RT_ERR_OK)
                 return retVal;

             if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA428, &regData)) != RT_ERR_OK)
                return retVal;

             regData &= ~(0x0200);
             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA428, regData)) != RT_ERR_OK)
                 return retVal;

             if((regValue & 0x00F0) == 0x00A0)
             {
                 if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA5D0, &regData)) != RT_ERR_OK)
                     return retVal;

                 regData |= 0x0006;
                 if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA5D0, regData)) != RT_ERR_OK)
                     return retVal;
             }
        }


    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_UTP_FIB_DET, 0x15BB)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x1303, 0x06D6)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x1304, 0x0700)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x13E2, 0x003F)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x13F9, 0x0090)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x121e, 0x03CA)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x1233, 0x0352)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x1237, 0x00a0)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x123a, 0x0030)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x1239, 0x0084)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x0301, 0x1000)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x1349, 0x001F)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicRegBit(0x18e0, 0, 0)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicRegBit(0x122b, 14, 1)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicRegBits(0x1305, 0xC000, 3)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC)
{
	ret_t retVal;
	rtk_uint32 regData;
	rtk_uint32 regAddr;

	/* Invalid input parameter */
	if(port >= RTL8367C_PORTNO)
		return RT_ERR_PORT_ID;

	if(bandwidth > RTL8367C_QOS_GRANULARTY_MAX)
		return RT_ERR_OUT_OF_RANGE;

	regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port);
	regData = bandwidth & RTL8367C_QOS_GRANULARTY_LSB_MASK;
	retVal = rtl8367c_setAsicReg(regAddr, regData);
	if(retVal != RT_ERR_OK)
		return retVal;

	regAddr += 1;
	regData = (bandwidth & RTL8367C_QOS_GRANULARTY_MSB_MASK) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET;
	retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, regData);
	if(retVal != RT_ERR_OK)
		return retVal;

	regAddr = RTL8367C_PORT_MISC_CFG_REG(port);
	retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, preifg);
	if(retVal != RT_ERR_OK)
		return retVal;

	regAddr = RTL8367C_PORT_MISC_CFG_REG(port);
	retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, enableFC);
	if(retVal != RT_ERR_OK)
		return retVal;

	return RT_ERR_OK;
}

ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate)
{
    ret_t retVal;
    rtk_uint32 regAddr, regData;

    if(port > RTL8367C_PORTIDMAX)
        return RT_ERR_PORT_ID;

    if(rate > RTL8367C_QOS_GRANULARTY_MAX)
        return RT_ERR_QOS_EBW_RATE;

    regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port);
    regData = RTL8367C_QOS_GRANULARTY_LSB_MASK & rate;

    retVal = rtl8367c_setAsicReg(regAddr, regData);

    if(retVal != RT_ERR_OK)
        return retVal;

    regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port);
    regData = (RTL8367C_QOS_GRANULARTY_MSB_MASK & rate) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET;

    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, regData);

	return retVal;
}

ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg)
{
    rtk_uint32 regData;
    ret_t retVal;

    regData = *(rtk_uint16*)pRmacfg;

    if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index))
        index = 0x04;
    else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f))
        index = 0x13;
    else if(index >= 0x22 && index <= 0x2F)
        index = 0x22;

    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority);
    if(retVal != RT_ERR_OK)
        return retVal;

    return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL00+index, regData);
}
ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode)
{
    ret_t   retVal;
    rtk_uint32 i, regValue, type, option;
    rtk_uint32 redData[][2] =   { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x21A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} };
    rtk_uint32 redDataSB[][2] = { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x31A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} };
    rtk_uint32 redData1[][2] =  { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
    rtk_uint32 redData5[][2] =  { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
    rtk_uint32 redData6[][2] =  { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
    rtk_uint32 redData8[][2] =  { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
    rtk_uint32 redData9[][2] =  { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
    rtk_uint32 redDataHB[][2] = { {0x82F0, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x7960, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };

    if(mode >= EXT_END)
        return RT_ERR_OUT_OF_RANGE;


    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
        return retVal;

    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
        return retVal;

    switch (regValue)
    {
        case 0x0276:
        case 0x0597:
        case 0x6367:
            type = 0;
            break;
        case 0x0652:
        case 0x6368:
            type = 1;
            break;
        default:
            return RT_ERR_FAILED;
    }


    if (0==type)
    {
        if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) )
        {
            if(id != 1)
                return RT_ERR_PORT_ID;

            if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0249)) != RT_ERR_OK)
                return retVal;

            if((retVal = rtl8367c_getAsicReg(0x13C1, &option)) != RT_ERR_OK)
                return retVal;

            if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0000)) != RT_ERR_OK)
                return retVal;
        }

        if(mode == EXT_GMII)
        {
            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT0_RGMXF, RTL8367C_EXT0_RGTX_INV_OFFSET, 1)) != RT_ERR_OK)
                return retVal;

            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT1_RGMXF, RTL8367C_EXT1_RGTX_INV_OFFSET, 1)) != RT_ERR_OK)
                return retVal;

            if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT1_GMII_TX_DELAY_MASK, 5)) != RT_ERR_OK)
                return retVal;

            if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT0_GMII_TX_DELAY_MASK, 6)) != RT_ERR_OK)
                return retVal;
        }

        /* Serdes reset */
        if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) )
        {
            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 1)) != RT_ERR_OK)
                return retVal;
        }
        else
        {
            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 0)) != RT_ERR_OK)
                return retVal;
        }

        if(mode == EXT_SGMII)
        {
            if(option == 0)
            {
                for(i = 0; i <= 7; i++)
                {
                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData[i][0])) != RT_ERR_OK)
                        return retVal;

                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData[i][1])) != RT_ERR_OK)
                        return retVal;

                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                        return retVal;
                }
            }
            else
            {
                for(i = 0; i <= 7; i++)
                {
                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataSB[i][0])) != RT_ERR_OK)
                        return retVal;

                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataSB[i][1])) != RT_ERR_OK)
                        return retVal;

                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                        return retVal;
                }
            }
        }

        if(mode == EXT_HSGMII)
        {
            if(option == 0)
            {
                if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK)
                    return retVal;

                if( (retVal = rtl8367c_getAsicReg(0x1301, &regValue)) != RT_ERR_OK)
                    return retVal;

                if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK)
                    return retVal;

                if ( ((regValue & 0x00F0) >> 4) == 0x0001)
                {
                    for(i = 0; i <= 8; i++)
                    {
                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData1[i][0])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData1[i][1])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                            return retVal;
                    }
                }
                else if ( ((regValue & 0x00F0) >> 4) == 0x0005)
                {
                    for(i = 0; i <= 8; i++)
                    {
                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData5[i][0])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData5[i][1])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                            return retVal;
                    }
                }
                else if ( ((regValue & 0x00F0) >> 4) == 0x0006)
                {
                    for(i = 0; i <= 8; i++)
                    {
                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData6[i][0])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData6[i][1])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                            return retVal;
                    }
                }
                else if ( ((regValue & 0x00F0) >> 4) == 0x0008)
                {
                    for(i = 0; i <= 8; i++)
                    {
                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData8[i][0])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData8[i][1])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                            return retVal;
                    }
                }
                else if ( ((regValue & 0x00F0) >> 4) == 0x0009)
                {
                    for(i = 0; i <= 8; i++)
                    {
                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData9[i][0])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData9[i][1])) != RT_ERR_OK)
                            return retVal;

                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                            return retVal;
                    }
                }
            }
            else
            {
                for(i = 0; i <= 8; i++)
                {
                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataHB[i][0])) != RT_ERR_OK)
                        return retVal;

                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataHB[i][1])) != RT_ERR_OK)
                        return retVal;

                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                        return retVal;
                }
            }
        }

        /* Only one ext port should care SGMII setting */
        if(id == 1)
        {
            if(mode == EXT_SGMII)
            {
                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 1)) != RT_ERR_OK)
                    return retVal;

                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK)
                    return retVal;
            }
            else if(mode == EXT_HSGMII)
            {
                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK)
                    return retVal;

                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 1)) != RT_ERR_OK)
                    return retVal;
            }
            else
            {
                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK)
                    return retVal;

                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK)
                    return retVal;
            }
        }

        if(0 == id || 1 == id)
        {
            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), mode)) != RT_ERR_OK)
                return retVal;
        }
        else
        {
            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, mode)) != RT_ERR_OK)
                return retVal;
        }

        /* Serdes not reset */
        if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) )
        {
            if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x7106)) != RT_ERR_OK)
                return retVal;

            if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK)
                return retVal;

            if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
                return retVal;
        }
    }

    return RT_ERR_OK;
}

ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility)
{
    rtk_uint32 retVal;
    rtk_uint32 reg_data;

    reg_data = (rtk_uint32)(*(rtk_uint16 *)pPortAbility);

    if(1 == id)
    {
        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
            return retVal;

        if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
            return retVal;

        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
            return retVal;

        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
            return retVal;

        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
            return retVal;
    }

	if(0 == id || 1 == id)
	    return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE + id, reg_data);
	else
	    return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, reg_data);
}

ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility)
{
    rtk_uint32  reg_data;
    rtk_uint32  sgmiiSel;
    rtk_uint32  hsgmiiSel;
    rtk_uint16  ability_data;
    ret_t       retVal;

    if(1 == id)
    {
        if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, &sgmiiSel)) != RT_ERR_OK)
            return retVal;

        if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgmiiSel)) != RT_ERR_OK)
            return retVal;

        if( (sgmiiSel == 1) || (hsgmiiSel == 1) )
        {
            memset(pPortAbility, 0x00, sizeof(rtl8367c_port_ability_t));
            pPortAbility->forcemode = 1;

            if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, &reg_data)) != RT_ERR_OK)
                return retVal;

            pPortAbility->duplex = reg_data;

            if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, &reg_data)) != RT_ERR_OK)
                return retVal;

            pPortAbility->speed = reg_data;

            if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, &reg_data)) != RT_ERR_OK)
                return retVal;

            pPortAbility->link = reg_data;

            if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, &reg_data)) != RT_ERR_OK)
                return retVal;

            pPortAbility->txpause = reg_data;

            if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, &reg_data)) != RT_ERR_OK)
                return retVal;

            pPortAbility->rxpause = reg_data;

            return RT_ERR_OK;
        }
    }

	if(0 == id || 1 == id)
	    retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE+id, &reg_data);
	else
	    retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, &reg_data);

    if(retVal != RT_ERR_OK)
        return retVal;

    ability_data = (rtk_uint16)reg_data;
    memcpy(pPortAbility, &ability_data, sizeof(rtl8367c_port_ability_t));

    return RT_ERR_OK;
}


rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability)
{
    rtk_api_ret_t retVal;
    rtl8367c_port_ability_t ability;
    rtk_uint32 ext_id;

    if(NULL == pPortability)
        return RT_ERR_NULL_POINTER;

    if (mode >=MODE_EXT_END)
        return RT_ERR_INPUT;

    ext_id = port - 15;

    if(mode == MODE_EXT_DISABLE)
    {
        memset(&ability, 0x00, sizeof(rtl8367c_port_ability_t));
        if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
            return retVal;

        if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK)
            return retVal;
    }
    else
    {
        if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK)
            return retVal;

        if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
            return retVal;

        ability.forcemode = pPortability->forcemode;
        ability.speed     = (mode == MODE_EXT_HSGMII) ? PORT_SPEED_1000M : pPortability->speed;
        ability.duplex    = pPortability->duplex;
        ability.link      = pPortability->link;
        ability.nway      = pPortability->nway;
        ability.txpause   = pPortability->txpause;
        ability.rxpause   = pPortability->rxpause;

        if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
            return retVal;
    }
    return RT_ERR_OK;
}

rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay)
{
    rtk_api_ret_t retVal;
    rtk_uint32 regAddr, regData;

    if ((txDelay > 1) || (rxDelay > 7))
        return RT_ERR_INPUT;

    if(port == EXT_PORT0)
        regAddr = RTL8367C_REG_EXT1_RGMXF;
    else if(port == EXT_PORT1)
        regAddr = RTL8367C_REG_EXT2_RGMXF;
    else
        return RT_ERR_INPUT;

    if ((retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
        return retVal;

    regData = (regData & 0xFFF0) | ((txDelay << 3) & 0x0008) | (rxDelay & 0x0007);

    if ((retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay)
{
    rtk_api_ret_t retVal;
    rtk_uint32 regAddr, regData;

    if( (NULL == pTxDelay) || (NULL == pRxDelay) )
        return RT_ERR_NULL_POINTER;

    if(port == EXT_PORT0)
        regAddr = RTL8367C_REG_EXT1_RGMXF;
    else if(port == EXT_PORT1)
        regAddr = RTL8367C_REG_EXT2_RGMXF;
    else
        return RT_ERR_INPUT;

    if ((retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
        return retVal;

    *pTxDelay = (regData & 0x0008) >> 3;
    *pRxDelay = regData & 0x0007;

    return RT_ERR_OK;
}

#define EEE_OCP_PHY_ADDR    (0xA5D0)

ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable)
{
    rtk_api_ret_t   retVal;
    rtk_uint32      regData;

    if(port >= RTL8367C_PORTNO)
        return RT_ERR_PORT_ID;

    if (enable > 1)
        return RT_ERR_INPUT;

    if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, &regData)) != RT_ERR_OK)
        return retVal;

    if(enable)
        regData |= (0x0001 << 1);
    else
        regData &= ~(0x0001 << 1);

    if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}
ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable)
{
    rtk_api_ret_t   retVal;
    rtk_uint32      regData;

    if(port >= RTL8367C_PORTNO)
        return RT_ERR_PORT_ID;

    if (enable > 1)
        return RT_ERR_INPUT;

    if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, &regData)) != RT_ERR_OK)
        return retVal;

    if(enable)
        regData |= (0x0001 << 2);
    else
        regData &= ~(0x0001 << 2);

    if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, int enable)
{
    rtk_api_ret_t   retVal;
    rtk_uint32      regData;
    rtk_uint32    phy_port;

    phy_port = l2p_port[port];

    if ((retVal = rtl8367c_setAsicEee100M(phy_port,enable))!=RT_ERR_OK)
        return retVal;
    if ((retVal = rtl8367c_setAsicEeeGiga(phy_port,enable))!=RT_ERR_OK)
        return retVal;

    if ((retVal = rtl8367c_setAsicPHYReg(phy_port, 0x1f, 0))!=RT_ERR_OK)
        return retVal;
    if ((retVal = rtl8367c_getAsicPHYReg(phy_port, 0, &regData))!=RT_ERR_OK)
        return retVal;
    regData |= 0x0200;
    if ((retVal = rtl8367c_setAsicPHYReg(phy_port, 0, regData))!=RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}

/* Function Name:
 *      rtk_switch_port_L2P_get
 * Description:
 *      Get physical port ID
 * Input:
 *      logicalPort       - logical port ID
 * Output:
 *      None
 * Return:
 *      Physical port ID
 * Note:
 *
 */
static rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort)
{
    if(logicalPort >= RTK_SWITCH_PORT_NUM)
        return UNDEFINE_PHY_PORT;

    return (l2p_port[logicalPort]);
}

/* Function Name:
 *      rtk_switch_isPortMaskValid
 * Description:
 *      Check portmask is valid or not
 * Input:
 *      pPmask       - logical port mask
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK           - port mask is valid
 *      RT_ERR_FAILED       - port mask is not valid
 *      RT_ERR_NOT_INIT     - Not Initialize
 *      RT_ERR_NULL_POINTER - Null pointer
 * Note:
 *
 */
rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask)
{
    if(NULL == pPmask)
        return RT_ERR_NULL_POINTER;

    if( (pPmask->bits[0] | valid_portmask) != valid_portmask )
        return RT_ERR_FAILED;
    else
        return RT_ERR_OK;
}


/* Function Name:
 *      rtl8367c_setAsicPortIsolationPermittedPortmask
 * Description:
 *      Set permitted port isolation portmask
 * Input:
 *      port 			- Physical port number (0~10)
 *      permitPortmask 	- port mask
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK 			- Success
 *      RT_ERR_SMI  		- SMI access error
 *      RT_ERR_PORT_ID  	- Invalid port number
 *      RT_ERR_PORT_MASK  	- Invalid portmask
 * Note:
 *      None
 */
ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask)
{
    if(port >= RTL8367C_PORTNO)
        return RT_ERR_PORT_ID;

    return rtl8367c_setAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), permitPortmask);
}


/* Function Name:
 *      rtk_switch_portmask_L2P_get
 * Description:
 *      Get physicl portmask from logical portmask
 * Input:
 *      pLogicalPmask       - logical port mask
 * Output:
 *      pPhysicalPortmask   - physical port mask
 * Return:
 *      RT_ERR_OK           - OK
 *      RT_ERR_NOT_INIT     - Not Initialize
 *      RT_ERR_NULL_POINTER - Null pointer
 *      RT_ERR_PORT_MASK    - Error port mask
 * Note:
 *
 */
rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask)
{
    rtk_uint32 log_port, phy_port;

    if(NULL == pLogicalPmask)
        return RT_ERR_NULL_POINTER;

    if(NULL == pPhysicalPortmask)
        return RT_ERR_NULL_POINTER;

    if(rtk_switch_isPortMaskValid(pLogicalPmask) != RT_ERR_OK)
        return RT_ERR_PORT_MASK;

    /* reset physical port mask */
    *pPhysicalPortmask = 0;

    RTK_PORTMASK_SCAN((*pLogicalPmask), log_port)
    {
        phy_port = rtk_switch_port_L2P_get((rtk_port_t)log_port);
        *pPhysicalPortmask |= (0x0001 << phy_port);
    }

    return RT_ERR_OK;
}


/* Function Name:
 *      rtk_port_isolation_set
 * Description:
 *      Set permitted port isolation portmask
 * Input:
 *      port         - port id.
 *      pPortmask    - Permit port mask
 * Output:
 *      None
 * Return:
 *      RT_ERR_OK           - OK
 *      RT_ERR_FAILED       - Failed
 *      RT_ERR_SMI          - SMI access error
 *      RT_ERR_PORT_ID      - Invalid port number.
 *      RT_ERR_PORT_MASK    - Invalid portmask.
 * Note:
 *      This API set the port mask that a port can trasmit packet to of each port
 *      A port can only transmit packet to ports included in permitted portmask
 */
rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask)
{
    rtk_api_ret_t retVal;
    rtk_uint32 pmask;

    if(NULL == pPortmask)
        return RT_ERR_NULL_POINTER;

    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK)
        return retVal;

    if ((retVal = rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), pmask)) != RT_ERR_OK)
        return retVal;

    return RT_ERR_OK;
}


ret_t rtl_init_switch(void)
{
	rtk_int32 retVal;
	rtl8367c_rma_t rmaCfg;
	rtk_port_mac_ability_t portAbility;
	rtk_port_t port;
	rtk_data_t txDelay;
	rtk_data_t rxDelay;
	rtk_portmask_t mask;

	if ((retVal = rtk_switch_init_8367c()) != RT_ERR_OK)
		return retVal;


	/* Set Old max packet length to 16K */
    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LENGTH_LIMINT_IPG, RTL8367C_MAX_LENTH_CTRL_MASK, 3)) != RT_ERR_OK)
        return retVal;

    if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX, RTL8367C_MAX_LEN_RX_TX_MASK, 3)) != RT_ERR_OK)
        return retVal;

    /* ACL Mode */
    if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_ACCESS_MODE, RTL8367C_ACL_ACCESS_MODE_MASK, 1)) != RT_ERR_OK)
        return retVal;

	/* Rate */
	if ((retVal = rtl8367c_setAsicPortIngressBandwidth(l2p_port[EXT_PORT0], RTL8367C_QOS_RATE_INPUT_MAX_HSG >> 3, 0, 1)) != RT_ERR_OK)
		return retVal;

	if ((retVal = rtl8367c_setAsicPortEgressRate(l2p_port[EXT_PORT0], RTL8367C_QOS_RATE_INPUT_MAX_HSG >> 3)) != RT_ERR_OK)
        return retVal;

	if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, 0)) != RT_ERR_OK)
		return retVal;

	if ((retVal = rtl8367c_setAsicReg(0x03fa, 0x0007)) != RT_ERR_OK)
        return retVal;

    /* Change unknown DA to per port setting */
    if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK, 3)) != RT_ERR_OK)
        return retVal;

	/* LUT lookup OP = 1 */
	if ((rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, 1)) != RT_ERR_OK)
		return retVal;

	/* Set RMA */
    rmaCfg.portiso_leaky = 0;
    rmaCfg.vlan_leaky = 0;
    rmaCfg.keep_format = 0;
    rmaCfg.trap_priority = 0;
    rmaCfg.discard_storm_filter = 0;
    rmaCfg.operation = 0;
    if ((retVal = rtl8367c_setAsicRma(2, &rmaCfg))!=RT_ERR_OK)
        return retVal;

    /* Enable TX Mirror isolation leaky */
    rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, 1);

    /* INT EN */
    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IO_MISC_FUNC, RTL8367C_INT_EN_OFFSET, 1)) != RT_ERR_OK)
        return retVal;

	/* config EXT_PORT1 with RGMII */
	memset(&portAbility, 0, sizeof(portAbility));
	portAbility.duplex = 1;
	portAbility.forcemode = 1;
	portAbility.speed = PORT_SPEED_1000M;
	portAbility.link = 1;
	portAbility.rxpause = 1;
	portAbility.txpause = 1;
	portAbility.nway = 0;
	if ((retVal = rtk_port_macForceLinkExt_set(EXT_PORT1, MODE_EXT_RGMII, &portAbility)) != RT_ERR_OK)
		return retVal;

	/* need config 2ns tx delay for rgmii here */
	if ((retVal = rtk_port_rgmiiDelayExt_get(EXT_PORT1, &txDelay, &rxDelay)) != RT_ERR_OK)
		return retVal;
	txDelay = 1;
	if ((retVal = rtk_port_rgmiiDelayExt_set(EXT_PORT1, txDelay, rxDelay)) != RT_ERR_OK)
		return retVal;

	/*uboot中关闭rtl8367 port forward，只在需要的时候开启port forward*/
	rtl8367c_disable_phyPort_forward();

#ifdef CFG_USE_SVLAN
	/* Isolate WAN to LAN */
#ifdef CFG_WAN_AT_P4
	RTK_PORTMASK_CLEAR(mask);
	RTK_PORTMASK_PORT_SET(mask, EXT_PORT1);
	rtk_port_isolation_set(UTP_PORT4, &mask);

	RTK_PORTMASK_CLEAR(mask);
	RTK_PORTMASK_PORT_SET(mask, EXT_PORT1);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT0);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT1);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT2);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT3);
	rtk_port_isolation_set(UTP_PORT0, &mask);
	rtk_port_isolation_set(UTP_PORT1, &mask);
	rtk_port_isolation_set(UTP_PORT2, &mask);
	rtk_port_isolation_set(UTP_PORT3, &mask);
#else /* CFG_WAN_AT_P0 */
	RTK_PORTMASK_CLEAR(mask);
	RTK_PORTMASK_PORT_SET(mask, EXT_PORT1);
	rtk_port_isolation_set(UTP_PORT0, &mask);

	RTK_PORTMASK_CLEAR(mask);
	RTK_PORTMASK_PORT_SET(mask, EXT_PORT1);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT1);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT2);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT3);
	RTK_PORTMASK_PORT_SET(mask, UTP_PORT4);
	rtk_port_isolation_set(UTP_PORT1, &mask);
	rtk_port_isolation_set(UTP_PORT2, &mask);
	rtk_port_isolation_set(UTP_PORT3, &mask);
	rtk_port_isolation_set(UTP_PORT4, &mask);
#endif
#else
	/* enable vlan */
	rtk_vlan_init();
#endif

	/* enable phy */
	for (port = 0; port < 5; port++)
	{
		rtl8367c_setAsicReg(0x2000 + (port << 5), 0x8140);
	}

	printf("---%s--- done\n", __func__);
	return RT_ERR_OK;
}

ret_t rtl8367c_enable_phyPort_forward(void)
{
	int index = UTP_PORT0;
	rtk_portmask_t mask;

	mask.bits[0] = 0x3001F;/* 0,1,2,3,4,16,17bit:UTP_PORT0-UTP_PORT4,EXT_PORT0,EXT_PORT1 */

	for(index =UTP_PORT0; index <=UTP_PORT7; index ++)
	{
		rtk_port_isolation_set(index, &mask);
	}

	return RT_ERR_OK;
}

ret_t rtl8367c_disable_phyPort_forward(void)
{
	int index = UTP_PORT0;
	rtk_portmask_t mask;

	mask.bits[0] = 0x0;/* all port isolation*/

	for(index =UTP_PORT0; index <=UTP_PORT7; index ++)
	{
		rtk_port_isolation_set(index, &mask);
	}

	return RT_ERR_OK;
}

