mirror of
git://nv-tegra.nvidia.com/kernel/nvethernetrm.git
synced 2025-12-22 09:12:10 +03:00
Issue: there is a PHY reset(RX_PCS_PHY_RDY) programming in Rx sequence that was disabling the Tx path from MGBE PCS Fix: Control entire programming sequence from SW and by pass HW FSM Bug 3359851 Bug 200765222 Change-Id: Iffd00d1dff00204e36eb3a14b19c07dcd3a502b8 Signed-off-by: Narayan Reddy <narayanr@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/2584394 Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> Reviewed-by: Bhadram Varka <vbhadram@nvidia.com> Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> GVS: Gerrit_Virtual_Submit
600 lines
16 KiB
C
600 lines
16 KiB
C
/*
|
|
* Copyright (c) 2020-2021, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "xpcs.h"
|
|
|
|
/**
|
|
* @brief xpcs_poll_for_an_complete - Polling for AN complete.
|
|
*
|
|
* Algorithm: This routine poll for AN completion status from
|
|
* XPCS IP.
|
|
*
|
|
* @param[in] osi_core: OSI core data structure.
|
|
* @param[out] an_status: AN status from XPCS
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core,
|
|
unsigned int *an_status)
|
|
{
|
|
void *xpcs_base = osi_core->xpcs_base;
|
|
unsigned int status = 0;
|
|
unsigned int retry = 1000;
|
|
unsigned int count;
|
|
int cond = 1;
|
|
|
|
/* 14. Poll for AN complete */
|
|
cond = 1;
|
|
count = 0;
|
|
while (cond == 1) {
|
|
if (count > retry) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"XPCS AN completion timed out\n", 0ULL);
|
|
return -1;
|
|
}
|
|
|
|
count++;
|
|
|
|
status = xpcs_read(xpcs_base, XPCS_VR_MII_AN_INTR_STS);
|
|
if ((status & XPCS_VR_MII_AN_INTR_STS_CL37_ANCMPLT_INTR) == 0U) {
|
|
/* autoneg not completed - poll */
|
|
osi_core->osd_ops.udelay(1000U);
|
|
} else {
|
|
/* 15. clear interrupt */
|
|
status &= ~XPCS_VR_MII_AN_INTR_STS_CL37_ANCMPLT_INTR;
|
|
xpcs_write(xpcs_base, XPCS_VR_MII_AN_INTR_STS, status);
|
|
cond = 0;
|
|
}
|
|
}
|
|
|
|
if ((status & XPCS_USXG_AN_STS_SPEED_MASK) == 0U) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"XPCS AN completed with zero speed\n", 0ULL);
|
|
return -1;
|
|
}
|
|
|
|
*an_status = status;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_set_speed - Set speed at XPCS
|
|
*
|
|
* Algorithm: This routine program XPCS speed based on AN status.
|
|
*
|
|
* @param[in] xpcs_base: XPCS base virtual address.
|
|
* @param[in] status: Autonegotation Status.
|
|
*/
|
|
static inline void xpcs_set_speed(void *xpcs_base,
|
|
unsigned int status)
|
|
{
|
|
unsigned int speed = status & XPCS_USXG_AN_STS_SPEED_MASK;
|
|
unsigned int ctrl = 0;
|
|
|
|
ctrl = xpcs_read(xpcs_base, XPCS_SR_MII_CTRL);
|
|
|
|
switch (speed) {
|
|
case XPCS_USXG_AN_STS_SPEED_2500:
|
|
/* 2.5Gbps */
|
|
ctrl |= XPCS_SR_MII_CTRL_SS5;
|
|
ctrl &= ~(XPCS_SR_MII_CTRL_SS6 | XPCS_SR_MII_CTRL_SS13);
|
|
break;
|
|
case XPCS_USXG_AN_STS_SPEED_5000:
|
|
/* 5Gbps */
|
|
ctrl |= (XPCS_SR_MII_CTRL_SS5 | XPCS_SR_MII_CTRL_SS13);
|
|
ctrl &= ~XPCS_SR_MII_CTRL_SS6;
|
|
break;
|
|
case XPCS_USXG_AN_STS_SPEED_10000:
|
|
default:
|
|
/* 10Gbps */
|
|
ctrl |= (XPCS_SR_MII_CTRL_SS6 | XPCS_SR_MII_CTRL_SS13);
|
|
ctrl &= ~XPCS_SR_MII_CTRL_SS5;
|
|
break;
|
|
}
|
|
|
|
xpcs_write(xpcs_base, XPCS_SR_MII_CTRL, ctrl);
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_start - Start XPCS
|
|
*
|
|
* Algorithm: This routine enables AN and set speed based on AN status
|
|
*
|
|
* @param[in] osi_core: OSI core data structure.
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
int xpcs_start(struct osi_core_priv_data *osi_core)
|
|
{
|
|
void *xpcs_base = osi_core->xpcs_base;
|
|
unsigned int an_status = 0;
|
|
unsigned int retry = RETRY_COUNT;
|
|
unsigned int count = 0;
|
|
unsigned int ctrl = 0;
|
|
int ret = 0;
|
|
int cond = COND_NOT_MET;
|
|
|
|
if (osi_core->xpcs_base == OSI_NULL) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"XPCS base is NULL", 0ULL);
|
|
/* TODO: Remove this once silicon arrives */
|
|
return 0;
|
|
}
|
|
|
|
if ((osi_core->phy_iface_mode == OSI_USXGMII_MODE_10G) ||
|
|
(osi_core->phy_iface_mode == OSI_USXGMII_MODE_5G)) {
|
|
ctrl = xpcs_read(xpcs_base, XPCS_SR_MII_CTRL);
|
|
ctrl |= XPCS_SR_MII_CTRL_AN_ENABLE;
|
|
xpcs_write(xpcs_base, XPCS_SR_MII_CTRL, ctrl);
|
|
|
|
ret = xpcs_poll_for_an_complete(osi_core, &an_status);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
xpcs_set_speed(xpcs_base, an_status);
|
|
|
|
/* USXGMII Rate Adaptor Reset before data transfer */
|
|
ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1);
|
|
ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_USRA_RST;
|
|
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl);
|
|
while (cond == COND_NOT_MET) {
|
|
if (count > retry) {
|
|
return -1;
|
|
}
|
|
|
|
count++;
|
|
|
|
ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1);
|
|
if ((ctrl & XPCS_VR_XS_PCS_DIG_CTRL1_USRA_RST) == 0U) {
|
|
cond = COND_MET;
|
|
} else {
|
|
osi_core->osd_ops.udelay(1000U);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* poll for Rx link up */
|
|
cond = COND_NOT_MET;
|
|
count = 0;
|
|
while (cond == COND_NOT_MET) {
|
|
if (count > retry) {
|
|
return -1;
|
|
}
|
|
|
|
count++;
|
|
|
|
ctrl = xpcs_read(xpcs_base, XPCS_SR_XS_PCS_STS1);
|
|
if ((ctrl & XPCS_SR_XS_PCS_STS1_RLU) ==
|
|
XPCS_SR_XS_PCS_STS1_RLU) {
|
|
cond = COND_MET;
|
|
} else {
|
|
osi_core->osd_ops.udelay(1000U);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_uphy_lane_bring_up - Bring up UPHY Tx/Rx lanes
|
|
*
|
|
* Algorithm: This routine bring up the UPHY Tx/Rx lanes
|
|
* through XPCS FSM wrapper.
|
|
*
|
|
* @param[in] osi_core: OSI core data structure.
|
|
* @param[in] lane_init_en: Tx/Rx lane init value.
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
static nve32_t xpcs_uphy_lane_bring_up(struct osi_core_priv_data *osi_core,
|
|
unsigned int lane_init_en)
|
|
{
|
|
void *xpcs_base = osi_core->xpcs_base;
|
|
nveu32_t retry = XPCS_RETRY_COUNT;
|
|
nve32_t cond = COND_NOT_MET;
|
|
nveu32_t val = 0;
|
|
nveu32_t count;
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)xpcs_base + XPCS_WRAP_UPHY_HW_INIT_CTRL);
|
|
val |= lane_init_en;
|
|
osi_writela(osi_core, val,
|
|
(nveu8_t *)xpcs_base + XPCS_WRAP_UPHY_HW_INIT_CTRL);
|
|
|
|
count = 0;
|
|
while (cond == COND_NOT_MET) {
|
|
if (count > retry) {
|
|
return -1;
|
|
}
|
|
count++;
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)xpcs_base + XPCS_WRAP_UPHY_HW_INIT_CTRL);
|
|
if ((val & lane_init_en) == OSI_NONE) {
|
|
/* exit loop */
|
|
cond = COND_MET;
|
|
} else {
|
|
osi_core->osd_ops.udelay(500U);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_check_pcs_lock_status - Checks whether PCS lock happened or not.
|
|
*
|
|
* Algorithm: This routine helps to check whether PCS lock happened or not.
|
|
*
|
|
* @param[in] osi_core: OSI core data structure.
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
static nve32_t xpcs_check_pcs_lock_status(struct osi_core_priv_data *osi_core)
|
|
{
|
|
void *xpcs_base = osi_core->xpcs_base;
|
|
nveu32_t retry = XPCS_RETRY_COUNT;
|
|
nve32_t cond = COND_NOT_MET;
|
|
nveu32_t val = 0;
|
|
nveu32_t count;
|
|
|
|
count = 0;
|
|
while (cond == COND_NOT_MET) {
|
|
if (count > retry) {
|
|
return -1;
|
|
}
|
|
count++;
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)xpcs_base + XPCS_WRAP_IRQ_STATUS);
|
|
if ((val & XPCS_WRAP_IRQ_STATUS_PCS_LINK_STS) ==
|
|
XPCS_WRAP_IRQ_STATUS_PCS_LINK_STS) {
|
|
/* exit loop */
|
|
cond = COND_MET;
|
|
} else {
|
|
osi_core->osd_ops.udelay(500U);
|
|
}
|
|
}
|
|
|
|
/* Clear the status */
|
|
osi_writela(osi_core, val, (nveu8_t *)xpcs_base + XPCS_WRAP_IRQ_STATUS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_lane_bring_up - Bring up UPHY Tx/Rx lanes
|
|
*
|
|
* Algorithm: This routine bring up the UPHY Tx/Rx lanes
|
|
* through XPCS FSM wrapper.
|
|
*
|
|
* @param[in] osi_core: OSI core data structure.
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
static nve32_t xpcs_lane_bring_up(struct osi_core_priv_data *osi_core)
|
|
{
|
|
unsigned int retry = 1000;
|
|
unsigned int count;
|
|
int cond;
|
|
nveu32_t cnt = 0;
|
|
nveu32_t val = 0;
|
|
#define PCS_RETRY_MAX 300
|
|
|
|
if (xpcs_uphy_lane_bring_up(osi_core,
|
|
XPCS_WRAP_UPHY_HW_INIT_CTRL_TX_EN) < 0) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"UPHY TX lane bring-up failed\n", 0ULL);
|
|
return -1;
|
|
}
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
/* Step1 RX_SW_OVRD */
|
|
val |= XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_SW_OVRD;
|
|
osi_writela(osi_core, val,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
/* Step2 RX_IDDQ */
|
|
val &= ~(XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_IDDQ);
|
|
osi_writela(osi_core, val,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
/* Step2 AUX_RX_IDDQ */
|
|
val &= ~(XPCS_WRAP_UPHY_RX_CONTROL_0_0_AUX_RX_IDDQ);
|
|
osi_writela(osi_core, val,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
/* Step3 RX_SLEEP */
|
|
val &= ~(XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_SLEEP);
|
|
osi_writela(osi_core, val,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
/* Step4 RX_CAL_EN */
|
|
val |= XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_CAL_EN;
|
|
osi_writela(osi_core, val,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
/* Step5 poll for Rx cal enable */
|
|
cond = COND_NOT_MET;
|
|
count = 0;
|
|
while (cond == COND_NOT_MET) {
|
|
if (count > retry) {
|
|
return -1;
|
|
}
|
|
|
|
count++;
|
|
|
|
val = osi_readla(osi_core,
|
|
(nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
if ((val & XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_CAL_EN) == 0) {
|
|
cond = COND_MET;
|
|
} else {
|
|
osi_core->osd_ops.udelay(1000U);
|
|
}
|
|
}
|
|
|
|
/* Step6 RX_DATA_EN */
|
|
val = osi_readla(osi_core, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
val |= XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_DATA_EN;
|
|
osi_writela(osi_core, val, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
|
|
while (cnt < PCS_RETRY_MAX) {
|
|
/* Step7 RX_CDR_RESET */
|
|
val = osi_readla(osi_core, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
val |= XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_CDR_RESET;
|
|
osi_writela(osi_core, val, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
/* Step8 RX_CDR_RESET */
|
|
val = osi_readla(osi_core, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
val &= ~(XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_CDR_RESET);
|
|
osi_writela(osi_core, val, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
val = osi_readla(osi_core, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
/* Step9 RX_PCS_PHY_RDY */
|
|
val |= XPCS_WRAP_UPHY_RX_CONTROL_0_0_RX_PCS_PHY_RDY;
|
|
osi_writela(osi_core, val, (nveu8_t *)osi_core->xpcs_base +
|
|
XPCS_WRAP_UPHY_RX_CONTROL_0_0);
|
|
|
|
if (xpcs_check_pcs_lock_status(osi_core) < 0) {
|
|
cnt += 1;
|
|
osi_core->osd_ops.udelay(1000U);
|
|
} else {
|
|
OSI_CORE_INFO(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"PCS block lock SUCCESS\n", 0ULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cnt == PCS_RETRY_MAX) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"Failed to get PCS block lock after max retries\n",
|
|
cnt);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_init - XPCS initialization
|
|
*
|
|
* Algorithm: This routine initialize XPCS in USXMII mode.
|
|
*
|
|
* @param[in] osi_core: OSI core data structure.
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
int xpcs_init(struct osi_core_priv_data *osi_core)
|
|
{
|
|
void *xpcs_base = osi_core->xpcs_base;
|
|
unsigned int retry = 1000;
|
|
unsigned int count;
|
|
unsigned int ctrl = 0;
|
|
int cond = 1;
|
|
|
|
if (osi_core->xpcs_base == OSI_NULL) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"XPCS base is NULL", 0ULL);
|
|
/* TODO: Remove this once silicon arrives */
|
|
return 0;
|
|
}
|
|
|
|
if (osi_core->pre_si != OSI_ENABLE) {
|
|
if (xpcs_lane_bring_up(osi_core) < 0) {
|
|
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
|
|
"TX/RX lane bring-up failed\n", 0ULL);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Switching to USXGMII Mode based on
|
|
* XPCS programming guideline 7.6
|
|
*/
|
|
|
|
/* 1. switch DWC_xpcs to BASE-R mode */
|
|
ctrl = xpcs_read(xpcs_base, XPCS_SR_XS_PCS_CTRL2);
|
|
ctrl |= XPCS_SR_XS_PCS_CTRL2_PCS_TYPE_SEL_BASE_R;
|
|
xpcs_write(xpcs_base, XPCS_SR_XS_PCS_CTRL2, ctrl);
|
|
|
|
/* 2. enable USXGMII Mode inside DWC_xpcs */
|
|
|
|
/* 3. USXG_MODE = 10G - default it will be 10G mode */
|
|
if ((osi_core->phy_iface_mode == OSI_USXGMII_MODE_10G) ||
|
|
(osi_core->phy_iface_mode == OSI_USXGMII_MODE_5G)) {
|
|
ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_KR_CTRL);
|
|
ctrl &= ~(XPCS_VR_XS_PCS_KR_CTRL_USXG_MODE_MASK);
|
|
|
|
if (osi_core->uphy_gbe_mode == OSI_DISABLE) {
|
|
ctrl |= XPCS_VR_XS_PCS_KR_CTRL_USXG_MODE_5G;
|
|
}
|
|
}
|
|
|
|
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_KR_CTRL, ctrl);
|
|
|
|
/* 4. Program PHY to operate at 10Gbps/5Gbps/2Gbps
|
|
* this step not required since PHY speed programming
|
|
* already done as part of phy INIT
|
|
*/
|
|
/* 5. Vendor specific software reset */
|
|
ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1);
|
|
ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_USXG_EN;
|
|
ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_VR_RST;
|
|
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl);
|
|
|
|
/* 6. Programming for Synopsys PHY - NA */
|
|
|
|
/* 7. poll until vendor specific software reset */
|
|
cond = 1;
|
|
count = 0;
|
|
while (cond == 1) {
|
|
if (count > retry) {
|
|
return -1;
|
|
}
|
|
|
|
count++;
|
|
|
|
ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1);
|
|
if ((ctrl & XPCS_VR_XS_PCS_DIG_CTRL1_VR_RST) == 0U) {
|
|
cond = 0;
|
|
} else {
|
|
osi_core->osd_ops.udelay(1000U);
|
|
}
|
|
}
|
|
|
|
/* 8. Backplane Ethernet PCS configurations
|
|
* clear AN_EN in SR_AN_CTRL
|
|
* set CL37_BP in VR_XS_PCS_DIG_CTRL1
|
|
*/
|
|
if ((osi_core->phy_iface_mode == OSI_USXGMII_MODE_10G) ||
|
|
(osi_core->phy_iface_mode == OSI_USXGMII_MODE_5G)) {
|
|
ctrl = xpcs_read(xpcs_base, XPCS_SR_AN_CTRL);
|
|
ctrl &= ~XPCS_SR_AN_CTRL_AN_EN;
|
|
xpcs_write(xpcs_base, XPCS_SR_AN_CTRL, ctrl);
|
|
|
|
ctrl = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1);
|
|
ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_CL37_BP;
|
|
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl);
|
|
}
|
|
/* TODO: 9. MII_AN_INTR_EN to 1, to enable auto-negotiation
|
|
* complete interrupt */
|
|
|
|
/* 10. (Optional step) Duration of link timer change */
|
|
|
|
/* 11. XPCS configured as MAC-side USGMII - NA */
|
|
|
|
/* 13. TODO: If there is interrupt enabled for AN interrupt */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief xpcs_eee - XPCS enable/disable EEE
|
|
*
|
|
* Algorithm: This routine update register related to EEE
|
|
* for XPCS.
|
|
*
|
|
* @param[in] xpcs_base: XPCS virtual base address
|
|
* @param[in] en_dis: enable - 1 or disable - 0
|
|
*
|
|
* @retval 0 on success
|
|
* @retval -1 on failure.
|
|
*/
|
|
int xpcs_eee(void *xpcs_base, unsigned int en_dis)
|
|
{
|
|
unsigned int val = 0x0U;
|
|
|
|
if (en_dis != OSI_ENABLE && en_dis != OSI_DISABLE) {
|
|
return -1;
|
|
}
|
|
|
|
if (xpcs_base == OSI_NULL)
|
|
return -1;
|
|
|
|
if (en_dis == OSI_DISABLE) {
|
|
val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0);
|
|
val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_LTX_EN;
|
|
val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_LRX_EN;
|
|
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0, val);
|
|
return 0;
|
|
}
|
|
|
|
/* 1. Check if DWC_xpcs supports the EEE feature by
|
|
* reading the SR_XS_PCS_EEE_ABL register
|
|
* 1000BASEX-Only is different config then else so can (skip) */
|
|
|
|
/* 2. Program various timers used in the EEE mode depending on the
|
|
* clk_eee_i clock frequency. default times are same as IEEE std
|
|
* clk_eee_i() is 102MHz. MULT_FACT_100NS = 9 because 9.8ns*10 = 98
|
|
* which is between 80 and 120 this leads to default setting match */
|
|
|
|
/* TODO for uFPGA */
|
|
|
|
val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0);
|
|
/* 3. If FEC is enabled in the KR mode (skip in FPGA)*/
|
|
/* 4. enable the EEE feature on the Tx path and Rx path */
|
|
//val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_EEE_SLR_BYP;
|
|
val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_LTX_EN;
|
|
val &= ~XPCS_VR_XS_PCS_EEE_MCTRL0_LRX_EN;
|
|
|
|
val |= (XPCS_VR_XS_PCS_EEE_MCTRL0_LTX_EN |
|
|
// XPCS_VR_XS_PCS_EEE_MCTRL0_LTX_EN |
|
|
XPCS_VR_XS_PCS_EEE_MCTRL0_LRX_EN);
|
|
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL0, val);
|
|
|
|
return 0;
|
|
}
|