From 35e6430484df1b904eeb0af738153cf3dab4d4bc Mon Sep 17 00:00:00 2001 From: Mohan Thadikamalla Date: Mon, 13 Jan 2020 14:57:01 +0530 Subject: [PATCH] nvethernetrm: Add PHY MDIO read/write callbacks Adds support for MDIO read/write callbacks and moves EQOS specific code from OSI layer to EQOS layer. Bug 200565891 Change-Id: I44d875ab88d8802266954c6d6362a795d22e89bb Signed-off-by: Bhadram Varka Signed-off-by: Mohan Thadikamalla Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/2223424 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: mobile promotions Reviewed-by: Narayan Reddy Reviewed-by: svc-mobile-coverity Reviewed-by: svc-mobile-misra Reviewed-by: svc-mobile-cert Reviewed-by: Bitan Biswas Reviewed-by: Bibek Basu Tested-by: mobile promotions GVS: Gerrit_Virtual_Submit --- include/osi_core.h | 9 +++ osi/core/eqos_core.c | 156 +++++++++++++++++++++++++++++++++++++++++++ osi/core/eqos_core.h | 12 ++++ osi/core/osi_core.c | 148 +++------------------------------------- 4 files changed, 186 insertions(+), 139 deletions(-) diff --git a/include/osi_core.h b/include/osi_core.h index f4043da..a56e814 100644 --- a/include/osi_core.h +++ b/include/osi_core.h @@ -253,6 +253,15 @@ struct osi_core_ops { void (*save_registers)(struct osi_core_priv_data *osi_core); /** Called to restore MAC control registers during SOC resume */ void (*restore_registers)(struct osi_core_priv_data *osi_core); + /** Called to write into a PHY reg over MDIO bus */ + int (*write_phy_reg)(struct osi_core_priv_data *osi_core, + unsigned int phyaddr, + unsigned int phyreg, + unsigned short phydata); + /** Called to read from a PHY reg over MDIO bus */ + int (*read_phy_reg)(struct osi_core_priv_data *osi_core, + unsigned int phyaddr, + unsigned int phyreg); }; /** diff --git a/osi/core/eqos_core.c b/osi/core/eqos_core.c index 61d2c9b..971d4c9 100644 --- a/osi/core/eqos_core.c +++ b/osi/core/eqos_core.c @@ -3467,6 +3467,160 @@ static inline void eqos_restore_registers(struct osi_core_priv_data *osi_core) } } +/** + * @brief poll_for_mii_idle Query the status of an ongoing DMA transfer + * + * @param[in] osi_core: OSI Core private data structure. + * + * @note MAC needs to be out of reset and proper clock configured. + * + * @retval 0 on Success + * @retval -1 on Failure + */ +static inline int poll_for_mii_idle(struct osi_core_priv_data *osi_core) +{ + /* half sec timeout */ + unsigned int retry = 50000; + unsigned int mac_gmiiar; + unsigned int count; + int cond = 1; + + count = 0; + while (cond == 1) { + if (count > retry) { + OSI_ERR(osi_core->osd, + OSI_LOG_ARG_HW_FAIL, + "MII operation timed out\n", + 0ULL); + return -1; + } + count++; + + mac_gmiiar = osi_readl((unsigned char *)osi_core->base + + EQOS_MAC_MDIO_ADDRESS); + if ((mac_gmiiar & EQOS_MAC_GMII_BUSY) == 0U) { + /* exit loop */ + cond = 0; + } else { + /* wait on GMII Busy set */ + osd_udelay(10U); + } + } + + return 0; +} + +static int eqos_write_phy_reg(struct osi_core_priv_data *osi_core, + unsigned int phyaddr, + unsigned int phyreg, + unsigned short phydata) +{ + unsigned int mac_gmiiar; + unsigned int mac_gmiidr; + int ret = 0; + + if (osi_core == OSI_NULL) { + OSI_ERR(OSI_NULL, OSI_LOG_ARG_INVALID, "osi_core is NULL\n", + 0ULL); + return -1; + } + + /* Wait for any previous MII read/write operation to complete */ + ret = poll_for_mii_idle(osi_core); + if (ret < 0) { + /* poll_for_mii_idle fail */ + return ret; + } + + mac_gmiidr = osi_readl((unsigned char *)osi_core->base + + EQOS_MAC_MDIO_DATA); + mac_gmiidr = ((mac_gmiidr & EQOS_MAC_GMIIDR_GD_WR_MASK) | + ((phydata) & EQOS_MAC_GMIIDR_GD_MASK)); + + osi_writel(mac_gmiidr, (unsigned char *)osi_core->base + + EQOS_MAC_MDIO_DATA); + + /* initiate the MII write operation by updating desired */ + /* phy address/id (0 - 31) */ + /* phy register offset */ + /* CSR Clock Range (20 - 35MHz) */ + /* Select write operation */ + /* set busy bit */ + mac_gmiiar = osi_readl((unsigned char *)osi_core->base + + EQOS_MAC_MDIO_ADDRESS); + mac_gmiiar = (mac_gmiiar & (EQOS_MDIO_PHY_REG_SKAP | + EQOS_MDIO_PHY_REG_C45E)); + mac_gmiiar = (mac_gmiiar | ((phyaddr) << EQOS_MDIO_PHY_ADDR_SHIFT) | + ((phyreg) << EQOS_MDIO_PHY_REG_SHIFT) | + ((osi_core->mdc_cr) << EQOS_MDIO_PHY_REG_CR_SHIF) | + (EQOS_MDIO_PHY_REG_WRITE) | EQOS_MAC_GMII_BUSY); + + osi_writel(mac_gmiiar, (unsigned char *)osi_core->base + + EQOS_MAC_MDIO_ADDRESS); + + /* wait for MII write operation to complete */ + ret = poll_for_mii_idle(osi_core); + if (ret < 0) { + /* poll_for_mii_idle fail */ + return ret; + } + + return ret; +} + +static int eqos_read_phy_reg(struct osi_core_priv_data *osi_core, + unsigned int phyaddr, + unsigned int phyreg) +{ + unsigned int mac_gmiiar; + unsigned int mac_gmiidr; + unsigned int data; + int ret = 0; + + if (osi_core == OSI_NULL) { + OSI_ERR(OSI_NULL, OSI_LOG_ARG_INVALID, "osi_core is NULL\n", + 0ULL); + return -1; + } + + /* wait for any previous MII read/write operation to complete */ + ret = poll_for_mii_idle(osi_core); + if (ret < 0) { + /* poll_for_mii_idle fail */ + return ret; + } + + mac_gmiiar = osi_readl((unsigned char *)osi_core->base + + EQOS_MAC_MDIO_ADDRESS); + /* initiate the MII read operation by updating desired */ + /* phy address/id (0 - 31) */ + /* phy register offset */ + /* CSR Clock Range (20 - 35MHz) */ + /* Select read operation */ + /* set busy bit */ + mac_gmiiar = (mac_gmiiar & (EQOS_MDIO_PHY_REG_SKAP | + EQOS_MDIO_PHY_REG_C45E)); + mac_gmiiar = mac_gmiiar | ((phyaddr) << EQOS_MDIO_PHY_ADDR_SHIFT) | + ((phyreg) << EQOS_MDIO_PHY_REG_SHIFT) | + (osi_core->mdc_cr) << EQOS_MDIO_PHY_REG_CR_SHIF | + (EQOS_MDIO_PHY_REG_GOC_READ) | EQOS_MAC_GMII_BUSY; + osi_writel(mac_gmiiar, (unsigned char *)osi_core->base + + EQOS_MAC_MDIO_ADDRESS); + + /* wait for MII write operation to complete */ + ret = poll_for_mii_idle(osi_core); + if (ret < 0) { + /* poll_for_mii_idle fail */ + return ret; + } + + mac_gmiidr = osi_readl((unsigned char *)osi_core->base + + EQOS_MAC_MDIO_DATA); + data = (mac_gmiidr & EQOS_MAC_GMIIDR_GD_MASK); + + return (int)data; +} + /** * @brief eqos_core_ops - EQOS MAC core operations */ @@ -3513,6 +3667,8 @@ static struct osi_core_ops eqos_core_ops = { .configure_eee = eqos_configure_eee, .save_registers = eqos_save_registers, .restore_registers = eqos_restore_registers, + .write_phy_reg = eqos_write_phy_reg, + .read_phy_reg = eqos_read_phy_reg, }; /** diff --git a/osi/core/eqos_core.h b/osi/core/eqos_core.h index baf55da..9f8f8cb 100644 --- a/osi/core/eqos_core.h +++ b/osi/core/eqos_core.h @@ -109,6 +109,8 @@ #define EQOS_MAC_LPI_EN_TIMER 0x00D8 #define EQOS_MAC_ANS 0x00E4 #define EQOS_MAC_PCS 0x00F8 +#define EQOS_MAC_MDIO_ADDRESS 0x0200 +#define EQOS_MAC_MDIO_DATA 0x0204 #define EQOS_5_00_MAC_ARPPA 0x0210 #define EQOS_MAC_MA0HR 0x0300 #define EQOS_MAC_ADDRH(x) ((0x0008U * (x)) + 0x0300U) @@ -369,6 +371,16 @@ #define EQOS_MAC_TCR_TSCTRLSSR OSI_BIT(9) #define EQOS_MAC_SSIR_SSINC_SHIFT 16U #define EQOS_MAC_STNSR_TSSS_MASK 0x7FFFFFFFU +#define EQOS_MAC_GMIIDR_GD_WR_MASK 0xFFFF0000U +#define EQOS_MAC_GMIIDR_GD_MASK 0xFFFFU +#define EQOS_MDIO_PHY_ADDR_SHIFT 21U +#define EQOS_MDIO_PHY_REG_SHIFT 16U +#define EQOS_MDIO_PHY_REG_CR_SHIF 8U +#define EQOS_MDIO_PHY_REG_WRITE OSI_BIT(2) +#define EQOS_MDIO_PHY_REG_GOC_READ (OSI_BIT(2) | OSI_BIT(3)) +#define EQOS_MDIO_PHY_REG_SKAP OSI_BIT(4) +#define EQOS_MDIO_PHY_REG_C45E OSI_BIT(1) +#define EQOS_MAC_GMII_BUSY 0x00000001U #define EQOS_DMA_CHX_STATUS_TPS OSI_BIT(1) #define EQOS_DMA_CHX_STATUS_TBU OSI_BIT(2) diff --git a/osi/core/osi_core.c b/osi/core/osi_core.c index e092b39..45790b4 100644 --- a/osi/core/osi_core.c +++ b/osi/core/osi_core.c @@ -23,157 +23,27 @@ #include #include -/** - * @addtogroup MDIO Macros - * @brief Helper MACROS for MDIO - * @{ - */ -#define MAC_MDIO_ADDRESS 0x200 -#define MAC_GMII_BUSY 0x00000001U - -#define MAC_MDIO_DATA 0x204 - -#define MAC_GMIIDR_GD_WR_MASK 0xffff0000U -#define MAC_GMIIDR_GD_MASK 0xffffU - -#define MDIO_PHY_ADDR_SHIFT 21U -#define MDIO_PHY_REG_SHIFT 16U -#define MDIO_MII_WRITE OSI_BIT(2) -/** @} */ - -/** - * @brief poll_for_mii_idle Query the status of an ongoing DMA transfer - * - * @param[in] osi_core: OSI Core private data structure. - * - * @note MAC needs to be out of reset and proper clock configured. - * - * @retval 0 on Success - * @retval -1 on Failure - */ -static inline int poll_for_mii_idle(struct osi_core_priv_data *osi_core) -{ - /* half sec timeout */ - unsigned int retry = 50000; - unsigned int mac_gmiiar; - unsigned int count; - int cond = 1; - - count = 0; - while (cond == 1) { - if (count > retry) { - OSI_ERR(osi_core->osd, - OSI_LOG_ARG_HW_FAIL, - "MII operation timed out\n", - 0ULL); - return -1; - } - - count++; - - mac_gmiiar = osi_readl((unsigned char *)osi_core->base + - MAC_MDIO_ADDRESS); - - if ((mac_gmiiar & MAC_GMII_BUSY) == 0U) { - cond = 0; - } else { - /* wait on GMII Busy set */ - osd_udelay(10U); - } - } - - return 0; -} - int osi_write_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, unsigned int phyreg, unsigned short phydata) { - unsigned int mac_gmiiar; - unsigned int mac_gmiidr; - int ret = 0; - - if (osi_core == OSI_NULL) { - return -1; + if ((osi_core != OSI_NULL) && (osi_core->ops != OSI_NULL) && + (osi_core->ops->write_phy_reg != OSI_NULL)) { + return osi_core->ops->write_phy_reg(osi_core, + phyaddr, phyreg, phydata); } - /* wait for any previous MII read/write operation to complete */ - ret = poll_for_mii_idle(osi_core); - if (ret < 0) { - return ret; - } - - mac_gmiidr = osi_readl((unsigned char *)osi_core->base + MAC_MDIO_DATA); - - mac_gmiidr = ((mac_gmiidr & MAC_GMIIDR_GD_WR_MASK) | - (((phydata) & MAC_GMIIDR_GD_MASK) << 0)); - - osi_writel(mac_gmiidr, (unsigned char *)osi_core->base + MAC_MDIO_DATA); - - /* initiate the MII write operation by updating desired */ - /* phy address/id (0 - 31) */ - /* phy register offset */ - /* CSR Clock Range (20 - 35MHz) */ - /* Select write operation */ - /* set busy bit */ - mac_gmiiar = osi_readl((unsigned char *)osi_core->base + MAC_MDIO_ADDRESS); - mac_gmiiar = (mac_gmiiar & 0x12U); - mac_gmiiar = (mac_gmiiar | ((phyaddr) << MDIO_PHY_ADDR_SHIFT) | - ((phyreg) << MDIO_PHY_REG_SHIFT) | - ((osi_core->mdc_cr) << 8U) | - MDIO_MII_WRITE | MAC_GMII_BUSY); - - osi_writel(mac_gmiiar, (unsigned char *)osi_core->base + MAC_MDIO_ADDRESS); - - /* wait for MII write operation to complete */ - ret = poll_for_mii_idle(osi_core); - if (ret < 0) { - return ret; - } - - return ret; + return -1; } int osi_read_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, unsigned int phyreg) { - unsigned int mac_gmiiar; - unsigned int mac_gmiidr; - unsigned int data; - int ret = 0; - - if (osi_core == OSI_NULL) { - return -1; + if ((osi_core != OSI_NULL) && (osi_core->ops != OSI_NULL) && + (osi_core->ops->read_phy_reg != OSI_NULL)) { + return osi_core->ops->read_phy_reg(osi_core, phyaddr, phyreg); } - /* wait for any previous MII read/write operation to complete */ - ret = poll_for_mii_idle(osi_core); - if (ret < 0) { - return ret; - } - - mac_gmiiar = osi_readl((unsigned char *)osi_core->base + MAC_MDIO_ADDRESS); - /* initiate the MII read operation by updating desired */ - /* phy address/id (0 - 31) */ - /* phy register offset */ - /* CSR Clock Range (20 - 35MHz) */ - /* Select read operation */ - /* set busy bit */ - mac_gmiiar = (mac_gmiiar & 0x12U); - mac_gmiiar = mac_gmiiar | ((phyaddr) << MDIO_PHY_ADDR_SHIFT) | - ((phyreg) << MDIO_PHY_REG_SHIFT) | - (osi_core->mdc_cr) << 8U | ((0x3U) << 2U) | MAC_GMII_BUSY; - osi_writel(mac_gmiiar, (unsigned char *)osi_core->base + MAC_MDIO_ADDRESS); - - /* wait for MII write operation to complete */ - ret = poll_for_mii_idle(osi_core); - if (ret < 0) { - return ret; - } - - mac_gmiidr = osi_readl((unsigned char *)osi_core->base + MAC_MDIO_DATA); - data = (mac_gmiidr & 0x0000FFFFU); - - return (int)data; + return -1; } int osi_init_core_ops(struct osi_core_priv_data *osi_core)