u-boot-2016/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.c
Ram Kumar D b8611c7623 driver: net: qca8084: add seperate configs for PHY & switch
Currently if CONFIG_QCA8084_PHY is enabled means, it will build
all qca8084 functions required for both PHY & switch mode. But,
some ipq devices might uses anyone of them. So, add configs to
seperate the PHY & switch mode and define it in corresponding
defconfig file as per the need.

Also, some of the qca8084 functions will be used only for debug
purpose, those functions are moved under the config QCA8084_DEBUG.

Thereby, we can save some space in the u-boot.

Change-Id: I7e5f53869629a0c7cbbb12daf04ed782c9693623
Signed-off-by: Ram Kumar D <quic_ramd@quicinc.com>
2022-07-11 13:15:03 +05:30

665 lines
20 KiB
C

/*
* Copyright (c) 2022, 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
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ipq_phy.h"
#include "ipq_qca8084.h"
#include "ipq_qca8084_clk.h"
#include "ipq_qca8084_interface_ctrl.h"
#include <malloc.h>
#ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args);
#else
#define pr_debug(fmt, args...)
#endif
extern void qca8084_phy_reset(u32 phy_id);
extern u16 qca8084_phy_reg_read(u32 phy_id, u32 reg_id);
extern u16 qca8084_phy_reg_write(u32 phy_id, u32 reg_id, u16 value);
extern u16 qca8084_phy_mmd_read(u32 phy_id, u16 mmd_num, u16 reg_id);
extern u16 qca8084_phy_mmd_write(u32 phy_id, u16 mmd_num, u16 reg_id,
u16 value);
extern void qca8084_phy_modify_mmd(uint32_t phy_addr, uint32_t mmd_num,
uint32_t mmd_reg, uint32_t mask, uint32_t value);
extern void qca8084_phy_modify_mii(uint32_t phy_addr, uint32_t mii_reg,
uint32_t mask, uint32_t value);
extern uint32_t ipq_mii_read(uint32_t reg);
extern void ipq_mii_write(uint32_t reg, uint32_t val);
extern void ipq_mii_update(uint32_t reg, uint32_t mask, uint32_t val);
extern void qca8084_port_clk_en_set(uint32_t qca8084_port_id, uint8_t mask,
uint8_t enable);
extern void qca8084_clk_assert(const char *clock_id);
extern void qca8084_port_clk_reset(uint32_t qca8084_port_id, uint8_t mask);
extern void qca8084_port_clk_rate_set(uint32_t qca8084_port_id, uint32_t rate);
#ifdef CONFIG_QCA8084_PHY_MODE
extern void qca8084_clk_deassert(const char *clock_id);
#endif
#ifdef CONFIG_QCA8084_SWT_MODE
extern void qca8084_uniphy_raw_clock_set(qca8084_clk_parent_t uniphy_clk,
uint64_t rate);
#endif
void qca8084_serdes_addr_get(uint32_t serdes_id, uint32_t *address)
{
uint32_t data = 0;
data = ipq_mii_read(SERDES_CFG_OFFSET);
switch(serdes_id)
{
case QCA8084_UNIPHY_SGMII_0:
*address = (data >> SERDES_CFG_S0_ADDR_BOFFSET) & 0x1f;
break;
case QCA8084_UNIPHY_SGMII_1:
*address = (data >> SERDES_CFG_S1_ADDR_BOFFSET) & 0x1f;
break;
case QCA8084_UNIPHY_XPCS:
*address = (data >> SERDES_CFG_S1_XPCS_ADDR_BOFFSET) & 0x1f;
break;
default:
pr_debug("Serdes id not matching\n");
break;
}
}
static void qca8084_uniphy_calibration(uint32_t uniphy_addr)
{
uint16_t uniphy_data = 0;
uint32_t retries = 100, calibration_done = 0;
/* wait calibration done to uniphy*/
while (calibration_done != QCA8084_UNIPHY_MMD1_CALIBRATION_DONE) {
mdelay(1);
if (retries-- == 0)
pr_debug("uniphy callibration time out!\n");
uniphy_data = qca8084_phy_mmd_read(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CALIBRATION4);
calibration_done = (uniphy_data & QCA8084_UNIPHY_MMD1_CALIBRATION_DONE);
}
}
void qca8084_port_speed_clock_set(uint32_t qca8084_port_id,
fal_port_speed_t speed)
{
uint32_t clk_rate = 0;
switch(speed)
{
case FAL_SPEED_2500:
clk_rate = UQXGMII_SPEED_2500M_CLK;
break;
case FAL_SPEED_1000:
clk_rate = UQXGMII_SPEED_1000M_CLK;
break;
case FAL_SPEED_100:
clk_rate = UQXGMII_SPEED_100M_CLK;
break;
case FAL_SPEED_10:
clk_rate = UQXGMII_SPEED_10M_CLK;
break;
default:
pr_debug("Unknown speed\n");
return;
}
qca8084_port_clk_rate_set(qca8084_port_id, clk_rate);
}
#ifdef CONFIG_QCA8084_PHY_MODE
void qca8084_ephy_addr_get(uint32_t qca8084_port_id, uint32_t *phy_addr)
{
uint32_t data = 0;
data = ipq_mii_read(EPHY_CFG_OFFSET);
switch(qca8084_port_id)
{
case PORT1:
*phy_addr = (data >> EPHY_CFG_EPHY0_ADDR_BOFFSET) & 0x1f;
break;
case PORT2:
*phy_addr = (data >> EPHY_CFG_EPHY1_ADDR_BOFFSET) & 0x1f;
break;
case PORT3:
*phy_addr = (data >> EPHY_CFG_EPHY2_ADDR_BOFFSET) & 0x1f;
break;
case PORT4:
*phy_addr = (data >> EPHY_CFG_EPHY3_ADDR_BOFFSET) & 0x1f;
break;
default:
pr_debug("qca8084_port_id not matching\n");
break;
}
}
static uint16_t qca8084_uniphy_xpcs_mmd_read(uint16_t mmd_num, uint16_t mmd_reg)
{
uint32_t uniphy_xpcs_addr = 0;
qca8084_serdes_addr_get(QCA8084_UNIPHY_XPCS, &uniphy_xpcs_addr);
return qca8084_phy_mmd_read(uniphy_xpcs_addr, mmd_num, mmd_reg);
}
static void qca8084_uniphy_xpcs_mmd_write(uint16_t mmd_num, uint16_t mmd_reg,
uint16_t reg_val)
{
uint32_t uniphy_xpcs_addr = 0;
#ifdef DEBUG
uint16_t phy_data = 0;
#endif
qca8084_serdes_addr_get(QCA8084_UNIPHY_XPCS, &uniphy_xpcs_addr);
qca8084_phy_mmd_write(uniphy_xpcs_addr, mmd_num, mmd_reg, reg_val);
/*check the mmd register value*/
#ifdef DEBUG
phy_data =
#endif
qca8084_uniphy_xpcs_mmd_read(mmd_num, mmd_reg);
pr_debug("phy_addr:0x%x, mmd_num:0x%x, mmd_reg:0x%x, phy_data:0x%x\n",
uniphy_xpcs_addr, mmd_num, mmd_reg, phy_data);
}
static void qca8084_uniphy_xpcs_modify_mmd(uint32_t mmd_num, uint32_t mmd_reg,
uint32_t mask, uint32_t value)
{
uint16_t phy_data = 0, new_phy_data = 0;
phy_data = qca8084_uniphy_xpcs_mmd_read(mmd_num, mmd_reg);
new_phy_data = (phy_data & ~mask) | value;
qca8084_uniphy_xpcs_mmd_write(mmd_num, mmd_reg, new_phy_data);
}
uint8_t qca8084_uniphy_mode_check(uint32_t uniphy_index,
qca8084_uniphy_mode_t uniphy_mode)
{
uint32_t uniphy_addr = 0;
uint16_t uniphy_mode_ctrl_data = 0;
qca8084_serdes_addr_get(uniphy_index, &uniphy_addr);
uniphy_mode_ctrl_data = qca8084_phy_mmd_read(uniphy_addr,
QCA8084_UNIPHY_MMD1, QCA8084_UNIPHY_MMD1_MODE_CTRL);
if(uniphy_mode_ctrl_data == PHY_INVALID_DATA)
return 0;
if(!(uniphy_mode & uniphy_mode_ctrl_data))
return 0;
return 1;
}
static uint32_t qca8084_uniphy_xpcs_port_to_mmd(uint32_t qca8084_port_id)
{
uint32_t mmd_id = 0;
switch(qca8084_port_id)
{
case PORT1:
mmd_id = QCA8084_UNIPHY_MMD31;
break;
case PORT2:
mmd_id = QCA8084_UNIPHY_MMD26;
break;
case PORT3:
mmd_id = QCA8084_UNIPHY_MMD27;
break;
case PORT4:
mmd_id = QCA8084_UNIPHY_MMD28;
break;
default:
pr_debug("Port not matching qca8084 ports\n");
}
return mmd_id;
}
static void qca8084_uniphy_xpcs_modify_port_mmd(uint32_t qca8084_port_id,
uint32_t mmd_reg, uint32_t mask,
uint32_t value)
{
uint32_t mmd_id = 0;
mmd_id = qca8084_uniphy_xpcs_port_to_mmd(qca8084_port_id);
qca8084_uniphy_xpcs_modify_mmd(mmd_id, mmd_reg, mask, value);
}
static void qca8084_uniphy_xpcs_8023az_enable(void)
{
uint16_t uniphy_data = 0;
uniphy_data = qca8084_uniphy_xpcs_mmd_read(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_AN_LP_BASE_ABL2);
if(!(uniphy_data & QCA8084_UNIPHY_MMD3_XPCS_EEE_CAP))
return;
/*Configure the EEE related timer*/
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL,
0x0f40, QCA8084_UNIPHY_MMD3_EEE_RES_REGS |
QCA8084_UNIPHY_MMD3_EEE_SIGN_BIT_REGS);
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_TX_TIMER,
0x1fff, QCA8084_UNIPHY_MMD3_EEE_TSL_REGS|
QCA8084_UNIPHY_MMD3_EEE_TLU_REGS |
QCA8084_UNIPHY_MMD3_EEE_TWL_REGS);
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_RX_TIMER,
0x1fff, QCA8084_UNIPHY_MMD3_EEE_100US_REG_REGS|
QCA8084_UNIPHY_MMD3_EEE_RWR_REG_REGS);
/*enable TRN_LPI*/
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL1,
0x101, QCA8084_UNIPHY_MMD3_EEE_TRANS_LPI_MODE|
QCA8084_UNIPHY_MMD3_EEE_TRANS_RX_LPI_MODE);
/*enable TX/RX LPI pattern*/
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL,
0x3, QCA8084_UNIPHY_MMD3_EEE_EN);
}
static void qca8084_uniphy_xpcs_10g_r_linkup(void)
{
uint16_t uniphy_data = 0;
uint32_t retries = 100, linkup = 0;
/* wait 10G_R link up */
while (linkup != QCA8084_UNIPHY_MMD3_10GBASE_R_UP) {
mdelay(1);
if (retries-- == 0)
pr_debug("10g_r link up timeout\n");
uniphy_data = qca8084_uniphy_xpcs_mmd_read(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_10GBASE_R_PCS_STATUS1);
linkup = (uniphy_data & QCA8084_UNIPHY_MMD3_10GBASE_R_UP);
}
}
static void qca8084_uniphy_xpcs_soft_reset(void)
{
uint16_t uniphy_data = 0;
uint32_t retries = 100, reset_done = QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET;
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_DIG_CTRL1, 0x8000,
QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET);
while (reset_done) {
mdelay(1);
if (retries-- == 0)
pr_debug("xpcs soft reset timeout\n");
uniphy_data = qca8084_uniphy_xpcs_mmd_read(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_DIG_CTRL1);
reset_done = (uniphy_data & QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET);
}
}
void qca8084_uniphy_xpcs_speed_set(uint32_t qca8084_port_id,
fal_port_speed_t speed)
{
uint32_t xpcs_speed = 0;
switch(speed)
{
case FAL_SPEED_2500:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_2500;
break;
case FAL_SPEED_1000:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_1000;
break;
case FAL_SPEED_100:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_100;
break;
case FAL_SPEED_10:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_10;
break;
default:
pr_debug("Unknown speed\n");
return;
}
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_CTRL,
QCA8084_UNIPHY_MMD_XPC_SPEED_MASK,
xpcs_speed);
}
void qca8084_uniphy_uqxgmii_function_reset(uint32_t qca8084_port_id)
{
uint32_t uniphy_addr = 0;
qca8084_serdes_addr_get(QCA8084_UNIPHY_SGMII_1, &uniphy_addr);
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_USXGMII_RESET, BIT(qca8084_port_id-1), 0);
mdelay(1);
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_USXGMII_RESET, BIT(qca8084_port_id-1),
BIT(qca8084_port_id-1));
if(qca8084_port_id == PORT1)
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD_MII_DIG_CTRL,
0x400, QCA8084_UNIPHY_MMD3_USXG_FIFO_RESET);
else
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_DIG_CTRL,
0x20, QCA8084_UNIPHY_MMD_USXG_FIFO_RESET);
}
void qca8084_uniphy_xpcs_autoneg_restart(uint32_t qca8084_port_id)
{
uint32_t retries = 500, uniphy_data = 0, mmd_id = 0;
mmd_id = qca8084_uniphy_xpcs_port_to_mmd(qca8084_port_id);
qca8084_uniphy_xpcs_modify_mmd(mmd_id, QCA8084_UNIPHY_MMD_MII_CTRL,
QCA8084_UNIPHY_MMD_MII_AN_RESTART, QCA8084_UNIPHY_MMD_MII_AN_RESTART);
mdelay(1);
uniphy_data = qca8084_uniphy_xpcs_mmd_read(mmd_id,
QCA8084_UNIPHY_MMD_MII_ERR_SEL);
while(!(uniphy_data & QCA8084_UNIPHY_MMD_MII_AN_COMPLETE_INT))
{
mdelay(1);
if (retries-- == 0)
{
pr_debug("xpcs uniphy autoneg restart timeout\n");
}
uniphy_data = qca8084_uniphy_xpcs_mmd_read(mmd_id,
QCA8084_UNIPHY_MMD_MII_ERR_SEL);
}
}
static void _qca8084_interface_uqxgmii_mode_set(uint32_t uniphy_addr)
{
uint32_t qca8084_port_id = 0, phy_addr = 0;
/*reset xpcs*/
pr_debug("reset xpcs\n");
qca8084_clk_assert(QCA8084_UNIPHY_XPCS_RST);
/*select xpcs mode*/
pr_debug("select xpcs mode\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_MODE_CTRL, 0x1f00, QCA8084_UNIPHY_MMD1_XPCS_MODE);
/*config dapa pass as usxgmii*/
pr_debug("config dapa pass as usxgmii\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_GMII_DATAPASS_SEL, QCA8084_UNIPHY_MMD1_DATAPASS_MASK,
QCA8084_UNIPHY_MMD1_DATAPASS_USXGMII);
/*reset and release uniphy GMII/XGMII and ethphy GMII*/
pr_debug("reset and release uniphy GMII/XGMII and ethphy GMII\n");
for(qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
qca8084_port_clk_reset(qca8084_port_id,
QCA8084_CLK_TYPE_UNIPHY|QCA8084_CLK_TYPE_EPHY);
}
/*ana sw reset and release*/
pr_debug("ana sw reset and release\n");
qca8084_phy_modify_mii(uniphy_addr,
QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RESET);
mdelay(10);
qca8084_phy_modify_mii(uniphy_addr,
QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RELEASE);
/*Wait calibration done*/
pr_debug("Wait calibration done\n");
qca8084_uniphy_calibration(uniphy_addr);
/*Enable SSCG(Spread Spectrum Clock Generator)*/
pr_debug("enable uniphy sscg\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CDA_CONTROL1, 0x8, QCA8084_UNIPHY_MMD1_SSCG_ENABLE);
/*release XPCS*/
pr_debug("release XPCS\n");
qca8084_clk_deassert(QCA8084_UNIPHY_XPCS_RST);
/*ethphy software reset*/
pr_debug("ethphy software reset\n");
for(qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
qca8084_ephy_addr_get(qca8084_port_id, &phy_addr);
qca8084_phy_reset(phy_addr);
}
/*Set BaseR mode*/
pr_debug("Set BaseR mode\n");
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_PCS_CTRL2, 0xf, QCA8084_UNIPHY_MMD3_PCS_TYPE_10GBASE_R);
/*wait 10G base_r link up*/
pr_debug("wait 10G base_r link up\n");
qca8084_uniphy_xpcs_10g_r_linkup();
/*enable UQXGMII mode*/
pr_debug("enable UQSXGMII mode\n");
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_DIG_CTRL1, 0x200, QCA8084_UNIPHY_MMD3_USXGMII_EN);
/*set UQXGMII mode*/
pr_debug("set QXGMII mode\n");
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_VR_RPCS_TPC, 0x1c00, QCA8084_UNIPHY_MMD3_QXGMII_EN);
/*set AM interval*/
pr_debug("set AM interval\n");
qca8084_uniphy_xpcs_mmd_write(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_MII_AM_INTERVAL, QCA8084_UNIPHY_MMD3_MII_AM_INTERVAL_VAL);
/*xpcs software reset*/
pr_debug("xpcs software reset\n");
qca8084_uniphy_xpcs_soft_reset();
}
void qca8084_interface_uqxgmii_mode_set(void)
{
uint32_t uniphy_addr = 0, qca8084_port_id = 0;
qca8084_serdes_addr_get(QCA8084_UNIPHY_SGMII_1, &uniphy_addr);
/*disable IPG_tuning bypass*/
pr_debug("disable IPG_tuning bypass\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_BYPASS_TUNING_IPG,
QCA8084_UNIPHY_MMD1_BYPASS_TUNING_IPG_EN, 0);
/*disable uniphy GMII/XGMII clock and disable ethphy GMII clock*/
pr_debug("disable uniphy GMII/XGMII clock and ethphy GMII clock\n");
for(qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
qca8084_port_clk_en_set(qca8084_port_id,
QCA8084_CLK_TYPE_UNIPHY|QCA8084_CLK_TYPE_EPHY, 0);
}
/*configure uqxgmii mode*/
pr_debug("configure uqxgmii mode\n");
_qca8084_interface_uqxgmii_mode_set(uniphy_addr);
/*enable auto-neg complete interrupt,Mii using mii-4bits,
configure as PHY mode, enable autoneg ability*/
pr_debug("enable auto-neg complete interrupt, Mii using mii-4bits,"
" configure as PHY mode, enable autoneg ability, disable TICD\n");
for (qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
/*enable auto-neg complete interrupt,Mii using mii-4bits,configure as PHY mode*/
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_AN_INT_MSK, 0x109,
QCA8084_UNIPHY_MMD_AN_COMPLETE_INT |
QCA8084_UNIPHY_MMD_MII_4BITS_CTRL |
QCA8084_UNIPHY_MMD_TX_CONFIG_CTRL);
/*enable autoneg ability*/
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_CTRL, 0x3060, QCA8084_UNIPHY_MMD_MII_AN_ENABLE |
QCA8084_UNIPHY_MMD_XPC_SPEED_1000);
/*disable TICD*/
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_XAUI_MODE_CTRL, 0x1,
QCA8084_UNIPHY_MMD_TX_IPG_CHECK_DISABLE);
}
/*enable EEE for xpcs*/
pr_debug("enable EEE for xpcs\n");
qca8084_uniphy_xpcs_8023az_enable();
}
#endif /* CONFIG_QCA8084_PHY_MODE */
#ifdef CONFIG_QCA8084_SWT_MODE
void qca8084_uniphy_sgmii_function_reset(u32 uniphy_index)
{
u32 uniphy_addr = 0;
qca8084_serdes_addr_get(uniphy_index, &uniphy_addr);
/*sgmii channel0 adpt reset*/
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CHANNEL0_CFG, QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET, 0);
mdelay(1);
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CHANNEL0_CFG, QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET,
QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET);
/*ipg tune reset*/
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_USXGMII_RESET, QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET, 0);
mdelay(1);
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_USXGMII_RESET, QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET,
QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET);
}
void qca8084_interface_sgmii_mode_set(u32 uniphy_index, u32 qca8084_port_id, mac_config_t *config)
{
u32 uniphy_addr = 0, mode_ctrl = 0, speed_mode = 0;
u32 uniphy_port_id = 0, ethphy_clk_mask = 0;
u64 raw_clk = 0;
/*get the uniphy address*/
qca8084_serdes_addr_get(uniphy_index, &uniphy_addr);
if(config->mac_mode == QCA8084_MAC_MODE_SGMII)
{
mode_ctrl = QCA8084_UNIPHY_MMD1_SGMII_MODE;
raw_clk = UNIPHY_CLK_RATE_125M;
}
else
{
mode_ctrl = QCA8084_UNIPHY_MMD1_SGMII_PLUS_MODE;
raw_clk = UNIPHY_CLK_RATE_312M;
}
if(config->clock_mode == QCA8084_INTERFACE_CLOCK_MAC_MODE)
mode_ctrl |= QCA8084_UNIPHY_MMD1_SGMII_MAC_MODE;
else
{
mode_ctrl |= QCA8084_UNIPHY_MMD1_SGMII_PHY_MODE;
/*eththy clock should be accessed for phy mode*/
ethphy_clk_mask = QCA8084_CLK_TYPE_EPHY;
}
pr_debug("uniphy:%d,mode:%s,autoneg_en:%d,force_speed:%d,clk_mask:0x%x\n",
uniphy_index, (config->mac_mode == QCA8084_MAC_MODE_SGMII)?"sgmii":"sgmii plus",
config->auto_neg, config->force_speed,
ethphy_clk_mask);
/*GMII interface clock disable*/
pr_debug("GMII interface clock disable\n");
qca8084_port_clk_en_set(qca8084_port_id, ethphy_clk_mask, 0);
/*when access uniphy0 clock, port5 should be used, but for phy mode,
the port 4 connect to uniphy0, so need to change the port id*/
if(uniphy_index == QCA8084_UNIPHY_SGMII_0)
uniphy_port_id = PORT5;
else
uniphy_port_id = qca8084_port_id;
qca8084_port_clk_en_set(uniphy_port_id, QCA8084_CLK_TYPE_UNIPHY, 0);
/*uniphy1 xpcs reset, and configure raw clk*/
if(uniphy_index == QCA8084_UNIPHY_SGMII_1)
{
pr_debug("uniphy1 xpcs reset, confiugre raw clock as:%lld\n",
raw_clk);
qca8084_clk_assert(QCA8084_UNIPHY_XPCS_RST);
qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY1_RX, raw_clk);
qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY1_TX, raw_clk);
}
else
{
pr_debug("uniphy0 configure raw clock as %lld\n", raw_clk);
qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY0_RX, raw_clk);
qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY0_TX, raw_clk);
}
/*configure SGMII mode or SGMII+ mode*/
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_MODE_CTRL, QCA8084_UNIPHY_MMD1_SGMII_MODE_CTRL_MASK,
mode_ctrl);
/*GMII datapass selection, 0 is for SGMII, 1 is for USXGMII*/
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_GMII_DATAPASS_SEL, QCA8084_UNIPHY_MMD1_DATAPASS_MASK, QCA8084_UNIPHY_MMD1_DATAPASS_SGMII);
/*configue force or autoneg*/
if(!config->auto_neg)
{
qca8084_port_speed_clock_set(qca8084_port_id,
config->force_speed);
switch (config->force_speed)
{
case FAL_SPEED_10:
speed_mode = QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE |
QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_10M;
break;
case FAL_SPEED_100:
speed_mode = QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE |
QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_100M;
break;
case FAL_SPEED_1000:
case FAL_SPEED_2500:
speed_mode = QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE |
QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_1G;
break;
default:
break;
}
}
else
{
speed_mode = QCA8084_UNIPHY_MMD1_CH0_AUTONEG_ENABLE;
}
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CHANNEL0_CFG, QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_MASK, speed_mode);
/*GMII interface clock reset and release\n*/
pr_debug("GMII interface clock reset and release\n");
qca8084_port_clk_reset(qca8084_port_id, ethphy_clk_mask);
qca8084_port_clk_reset(uniphy_port_id, QCA8084_CLK_TYPE_UNIPHY);
/*analog software reset and release*/
pr_debug("analog software reset and release\n");
qca8084_phy_modify_mii(uniphy_addr,
QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RESET);
mdelay(1);
qca8084_phy_modify_mii(uniphy_addr,
QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RELEASE);
/*wait uniphy calibration done*/
pr_debug("wait uniphy calibration done\n");
qca8084_uniphy_calibration(uniphy_addr);
/*GMII interface clock enable*/
pr_debug("GMII interface clock enable\n");
qca8084_port_clk_en_set(qca8084_port_id, ethphy_clk_mask, 1);
qca8084_port_clk_en_set(uniphy_port_id, QCA8084_CLK_TYPE_UNIPHY, 1);
return;
}
#endif /* CONFIG_QCA8084_SWT_MODE */