core: add pcs register readback after write support

As per T23X-MGBE_HSIv2-14 requirement for PCS register
we need to perform readback for each write operation
to verify write operation was successful

Bug 3606649
Change-Id: I7cca6baa43feaa4207b6158f0abc796e656338dd
Signed-off-by: Om Prakash Singh <omp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/2700845
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Om Prakash Singh
2022-04-21 15:17:24 +05:30
committed by Bhadram Varka
parent e0e2a6b200
commit 0c754dc009
6 changed files with 129 additions and 41 deletions

View File

@@ -42,6 +42,7 @@ static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core,
unsigned int retry = 1000;
unsigned int count;
int cond = 1;
int ret = 0;
/* 14. Poll for AN complete */
cond = 1;
@@ -70,7 +71,10 @@ static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core,
} 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);
ret = xpcs_write_safety(osi_core, XPCS_VR_MII_AN_INTR_STS, status);
if (ret != 0) {
return ret;
}
cond = 0;
}
}
@@ -90,14 +94,18 @@ static inline int xpcs_poll_for_an_complete(struct osi_core_priv_data *osi_core,
*
* Algorithm: This routine program XPCS speed based on AN status.
*
* @param[in] xpcs_base: XPCS base virtual address.
* @param[in] osi_core: OSI core data structure.
* @param[in] status: Autonegotation Status.
*
* @retval 0 on success
* @retval -1 on failure
*/
static inline void xpcs_set_speed(void *xpcs_base,
static inline int xpcs_set_speed(struct osi_core_priv_data *osi_core,
unsigned int status)
{
unsigned int speed = status & XPCS_USXG_AN_STS_SPEED_MASK;
unsigned int ctrl = 0;
void *xpcs_base = osi_core->xpcs_base;
ctrl = xpcs_read(xpcs_base, XPCS_SR_MII_CTRL);
@@ -120,7 +128,7 @@ static inline void xpcs_set_speed(void *xpcs_base,
break;
}
xpcs_write(xpcs_base, XPCS_SR_MII_CTRL, ctrl);
return xpcs_write_safety(osi_core, XPCS_SR_MII_CTRL, ctrl);
}
/**
@@ -154,15 +162,19 @@ int xpcs_start(struct osi_core_priv_data *osi_core)
(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_write_safety(osi_core, XPCS_SR_MII_CTRL, ctrl);
if (ret != 0) {
return ret;
}
ret = xpcs_poll_for_an_complete(osi_core, &an_status);
if (ret < 0) {
return ret;
}
xpcs_set_speed(xpcs_base, an_status);
ret = xpcs_set_speed(osi_core, an_status);
if (ret != 0) {
return ret;
}
/* 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;
@@ -446,6 +458,7 @@ int xpcs_init(struct osi_core_priv_data *osi_core)
unsigned int count;
unsigned int ctrl = 0;
int cond = 1;
int ret = 0;
if (osi_core->xpcs_base == OSI_NULL) {
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
@@ -469,8 +482,10 @@ int xpcs_init(struct osi_core_priv_data *osi_core)
/* 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);
ret = xpcs_write_safety(osi_core, XPCS_SR_XS_PCS_CTRL2, ctrl);
if (ret != 0) {
return ret;
}
/* 2. enable USXGMII Mode inside DWC_xpcs */
/* 3. USXG_MODE = 10G - default it will be 10G mode */
@@ -484,8 +499,10 @@ int xpcs_init(struct osi_core_priv_data *osi_core)
}
}
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_KR_CTRL, ctrl);
ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_KR_CTRL, ctrl);
if (ret != 0) {
return ret;
}
/* 4. Program PHY to operate at 10Gbps/5Gbps/2Gbps
* this step not required since PHY speed programming
* already done as part of phy INIT
@@ -493,6 +510,14 @@ int xpcs_init(struct osi_core_priv_data *osi_core)
/* 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;
ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl);
if (ret != 0) {
return ret;
}
/* XPCS_VR_XS_PCS_DIG_CTRL1_VR_RST bit is self clearing
* value readback varification is not needed
*/
ctrl |= XPCS_VR_XS_PCS_DIG_CTRL1_VR_RST;
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl);
@@ -524,11 +549,16 @@ int xpcs_init(struct osi_core_priv_data *osi_core)
(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);
ret = xpcs_write_safety(osi_core, XPCS_SR_AN_CTRL, ctrl);
if (ret != 0) {
return ret;
}
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);
ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_DIG_CTRL1, ctrl);
if (ret != 0) {
return ret;
}
}
/* TODO: 9. MII_AN_INTR_EN to 1, to enable auto-negotiation
@@ -549,15 +579,17 @@ int xpcs_init(struct osi_core_priv_data *osi_core)
* Algorithm: This routine update register related to EEE
* for XPCS.
*
* @param[in] xpcs_base: XPCS virtual base address
* @param[in] osi_core: OSI core data structure.
* @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)
int xpcs_eee(struct osi_core_priv_data *osi_core, unsigned int en_dis)
{
void *xpcs_base = osi_core->xpcs_base;
unsigned int val = 0x0U;
int ret = 0;
if (en_dis != OSI_ENABLE && en_dis != OSI_DISABLE) {
return -1;
@@ -570,7 +602,10 @@ int xpcs_eee(void *xpcs_base, unsigned int en_dis)
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);
ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_EEE_MCTRL0, val);
if (ret != 0) {
return ret;
}
return 0;
}
@@ -588,12 +623,16 @@ int xpcs_eee(void *xpcs_base, unsigned int en_dis)
/* 4. enable the EEE feature on the Tx path and Rx path */
val |= (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);
ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_EEE_MCTRL0, val);
if (ret != 0) {
return ret;
}
/* Transparent Tx LPI Mode Enable */
val = xpcs_read(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL1);
val |= XPCS_VR_XS_PCS_EEE_MCTRL1_TRN_LPI;
xpcs_write(xpcs_base, XPCS_VR_XS_PCS_EEE_MCTRL1, val);
ret = xpcs_write_safety(osi_core, XPCS_VR_XS_PCS_EEE_MCTRL1, val);
if (ret != 0) {
return ret;
}
return 0;
}