openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

cmicx_miim.c (17805B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * CMICx MIIM (MDIO) functions
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <sal/core/libc.h>
     12 #include <sal/core/boot.h>
     13 #include <soc/debug.h>
     14 #include <soc/cm.h>
     15 #include <soc/drv.h>
     16 #include <soc/error.h>
     17 #include <sal/core/sync.h>
     18 #include <soc/util.h>
     19 #include <soc/cmic.h>
     20 
     21 #ifdef _ERR_MSG_MODULE_NAME
     22 #error "_ERR_MSG_MODULE_NAME redefined"
     23 #endif
     24 #define _ERR_MSG_MODULE_NAME BSL_LS_SOC_MIIM
     25 
     26 #ifdef BCM_CMICX_SUPPORT
     27 #include <soc/cmicx.h>
     28 #include <soc/cmicx_miim.h>
     29 #include <soc/iproc.h>
     30 #endif
     31 
     32 #if (defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT))
     33 #include <soc/dnxc/dnxc_ha.h>
     34 #endif
     35 
     36 #if defined(BCM_DNX_SUPPORT)
     37 #include <soc/dnx/dnx_err_recovery_manager.h>
     38 #include <soc/dnx/dnx_data/auto_generated/dnx_data_access.h>
     39 #endif
     40 
     41 #include <soc/phyreg.h>
     42 #include <soc/linkctrl.h>
     43 
     44 #ifdef BCM_CMICX_SUPPORT
     45 
     46 /* determine if device supports iProc15 */
     47 int soc_is_miim_12r(int unit)
     48 {
     49     int is_miim_12r = 0;
     50 
     51     /* iProc 15 devices support 12 MDIO rings */
     52     if (SOC_IS_TOMAHAWK3(unit) || SOC_IS_HELIX5(unit)) {
     53         is_miim_12r = 1;
     54     }
     55 
     56     return is_miim_12r;
     57 }
     58 
     59 uint32 soc_cmicx_miim_cycle_type_get(int unit, int is_write, int clause45, uint32 phy_devad)
     60 {
     61     uint32 cycle_type = 0;
     62     int is_miim_12r = 0;
     63 
     64     /* iProc 15 devices support 12 MDIO rings */
     65     if (soc_is_miim_12r(unit)) {
     66         is_miim_12r = 1;
     67     }
     68 
     69     if (clause45) {
     70         if(is_write) {
     71             if (phy_devad & MIIM_CYCLE_C45_WR) {
     72                 cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C45_REG_WR : MIIM_CYCLE_C45_REG_WR;
     73             } else if (phy_devad & MIIM_CYCLE_C45_WR_AD) {
     74                 cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C45_REG_AD : MIIM_CYCLE_C45_REG_AD;
     75             } else {
     76                 cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C45_AUTO_WR : MIIM_CYCLE_AUTO;
     77             }
     78         } else {
     79             if (phy_devad & MIIM_CYCLE_C45_RD) {
     80                 cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C45_REG_RD : MIIM_CYCLE_C45_REG_RD;
     81             } else if (phy_devad & MIIM_CYCLE_C45_RD_ADINC) {
     82                 cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C45_REG_RD_ADINC : MIIM_CYCLE_C45_REG_RD_ADINC;
     83             } else {
     84                 cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C45_AUTO_RD : MIIM_CYCLE_AUTO;
     85             }
     86         }
     87     } else {
     88         /* clause 22 */
     89         if (is_write) {
     90             cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C22_REG_WR : MIIM_CYCLE_C22_REG_WR;
     91         } else {
     92             cycle_type = is_miim_12r ? MIIM_CYCLE_12R_C22_REG_RD : MIIM_CYCLE_C22_REG_RD;
     93         }
     94     }
     95 
     96     LOG_DEBUG(BSL_LS_SOC_MIIM, (BSL_META_U(unit, "is_miim_12r %d, cycle_type %d\n"), is_miim_12r, cycle_type));
     97 
     98     return cycle_type;
     99 }
    100 
    101 /** see .h file   */
    102 int
    103 soc_cmicx_miim_init(int unit)
    104 {
    105     uint32 reg_val;
    106 
    107     /* Give MDIO control to IPROC */
    108     READ_MIIM_COMMON_CONTROLr(unit, &reg_val);
    109     soc_reg_field_set(unit, MIIM_COMMON_CONTROLr, &reg_val, OVRD_EXT_MDIO_MSTR_CNTRLf, 1);
    110     WRITE_MIIM_COMMON_CONTROLr(unit, reg_val);
    111 
    112     return SOC_E_NONE;
    113 }
    114 
    115 /**
    116  * \brief
    117  *   Function to get the correct register name and the register address
    118  *   in dependence of the ring that should be access
    119  *
    120  * \param [in] unit - Unit #
    121  * \param [in] ring_index - ring index to be access #
    122  * \param [out] ring_reg - ring register name #
    123  * \param [out] reg_addr - ring register address #
    124  *
    125  * \return
    126  *     err - see shr_error_e
    127  * \remark
    128  *   * None
    129  * \see
    130  *   * None
    131  */
    132 static int
    133 soc_cmicx_miim_ring_reg_addr_get(int unit, int ring_index, soc_reg_t * ring_reg, uint32 * reg_addr)
    134 {
    135     soc_reg_t ring_control_8r_reg[] = {MIIM_RING0_CONTROLr,
    136                                        MIIM_RING1_CONTROLr,
    137                                        MIIM_RING2_CONTROLr,
    138                                        MIIM_RING3_CONTROLr,
    139                                        MIIM_RING4_CONTROLr,
    140                                        MIIM_RING5_CONTROLr,
    141                                        MIIM_RING6_CONTROLr,
    142                                        MIIM_RING7_CONTROLr,
    143                                        INVALIDr};
    144 
    145     soc_reg_t ring_control_12r_reg[] = {MIIM_RING0_CONTROLr,
    146                                         MIIM_RING1_CONTROLr,
    147                                         MIIM_RING2_CONTROLr,
    148                                         MIIM_RING3_CONTROLr,
    149                                         MIIM_RING4_CONTROLr,
    150                                         MIIM_RING5_CONTROLr,
    151                                         MIIM_RING6_CONTROLr,
    152                                         MIIM_RING7_CONTROLr,
    153                                         MIIM_RING8_CONTROLr,
    154                                         MIIM_RING9_CONTROLr,
    155                                         MIIM_RING10_CONTROLr,
    156                                         MIIM_RING11_CONTROLr,
    157                                         INVALIDr};
    158     soc_reg_t *ring_control_reg = NULL;
    159 
    160     int ring_idx_end = 0;
    161 
    162     /* determine mdio ring end based on if this is iProc14 of iProc15 device */
    163     ring_idx_end = soc_is_miim_12r(unit) ? CMICX_MIIM_12R_RING_INDEX_END : CMICX_MIIM_RING_INDEX_END;
    164 
    165     if ((ring_index < CMICX_MIIM_RING_INDEX_START) ||
    166         (ring_index > ring_idx_end)) {
    167         LOG_ERROR(BSL_LS_SOC_MIIM, (BSL_META_U(unit, "Invalid CMICx MIIM Ring index %d\n"), ring_index));
    168         return SOC_E_PARAM;
    169     }
    170 
    171     ring_control_reg = soc_is_miim_12r(unit) ? ring_control_12r_reg : ring_control_8r_reg;
    172 
    173     *ring_reg = ring_control_reg[ring_index];
    174 
    175     *reg_addr = soc_reg_addr(unit, *ring_reg, REG_PORT_ANY, 0);
    176 
    177     return SOC_E_NONE;
    178 }
    179 
    180 /**
    181  * \brief
    182  *   Function to get the divisor delay of the given ring
    183  *
    184  * \param [in] unit - Unit #
    185  * \param [in] ring_index - ring index to be access #
    186  * \param [out] out_delay - ring out divisor delay value #
    187  *
    188  * \return
    189  *     err - see shr_error_e
    190  * \remark
    191  *   * None
    192  * \see
    193  *   * None
    194  */
    195 int
    196 soc_cmicx_miim_divider_ring_delay_set(int unit, int ring_index, int out_delay)
    197 {
    198     uint32 reg_val, reg_addr;
    199     soc_reg_t ring_reg;
    200     SOC_INIT_FUNC_DEFS;
    201 
    202     _SOC_IF_ERR_EXIT(soc_cmicx_miim_ring_reg_addr_get(unit, ring_index, &ring_reg, &reg_addr));
    203 
    204     soc_iproc_getreg(unit, reg_addr, &reg_val);
    205 
    206     if (out_delay != MIIM_INTERNAL_EXTERNAL_DELAY_INVALID) {
    207         soc_reg_field_set(unit, ring_reg, &reg_val, MDIO_OUT_DELAYf, out_delay);
    208     }
    209 
    210     soc_iproc_setreg(unit, reg_addr, reg_val);
    211 
    212 exit:
    213     SOC_FUNC_RETURN;
    214 }
    215 
    216 /**
    217  * \brief
    218  *   Function to set the divisor delay of the given ring
    219  *
    220  * \param [in] unit - Unit #
    221  * \param [in] ring_index - ring index to be access #
    222  * \param [int] out_delay - ring out divisor delay value #
    223  *
    224  * \return
    225  *     err - see shr_error_e
    226  * \remark
    227  *   * None
    228  * \see
    229  *   * None
    230  */
    231 int
    232 soc_cmicx_miim_divider_ring_delay_get(int unit, int ring_index, int * out_delay)
    233 {
    234     uint32 reg_val, reg_addr;
    235     soc_reg_t ring_reg;
    236     SOC_INIT_FUNC_DEFS;
    237 
    238     _SOC_IF_ERR_EXIT(soc_cmicx_miim_ring_reg_addr_get(unit, ring_index, &ring_reg, &reg_addr));
    239 
    240     soc_iproc_getreg(unit, reg_addr, &reg_val);
    241 
    242     *out_delay = soc_reg_field_get(unit, ring_reg, reg_val, MDIO_OUT_DELAYf);
    243 
    244 exit:
    245     SOC_FUNC_RETURN;
    246 }
    247 
    248 /** see .h file   */
    249 int
    250 soc_cmicx_miim_divider_set_ring(int unit, int ring_index, int int_divider, int ext_divider, int out_delay)
    251 {
    252     uint32 reg_val, reg_addr;
    253     soc_reg_t ring_reg;
    254     SOC_INIT_FUNC_DEFS;
    255 
    256     _SOC_IF_ERR_EXIT(soc_cmicx_miim_ring_reg_addr_get(unit, ring_index, &ring_reg, &reg_addr));
    257 
    258     soc_iproc_getreg(unit, reg_addr, &reg_val);
    259 
    260     if (int_divider != -1) {
    261         soc_reg_field_set(unit, ring_reg, &reg_val, CLOCK_DIVIDER_INTf, int_divider);
    262     }
    263 
    264     if (ext_divider != -1) {
    265         soc_reg_field_set(unit, ring_reg, &reg_val, CLOCK_DIVIDER_EXTf, ext_divider);
    266     }
    267 
    268     if (out_delay != -1) {
    269         soc_reg_field_set(unit, ring_reg, &reg_val, MDIO_OUT_DELAYf, out_delay);
    270     }
    271 
    272     soc_iproc_setreg(unit, reg_addr, reg_val);
    273 
    274 exit:
    275     SOC_FUNC_RETURN;
    276 }
    277 
    278 /** see .h file   */
    279 int
    280 soc_cmicx_miim_divider_set_all(int unit, int int_divider, int ext_divider, int out_delay)
    281 {
    282     int ring_idx = 0;
    283     int ring_idx_end = 0;
    284 
    285     /* determine mdio ring end based on if this is iProc14 of iProc15 device */
    286     ring_idx_end = soc_is_miim_12r(unit) ? CMICX_MIIM_12R_RING_INDEX_END : CMICX_MIIM_RING_INDEX_END;
    287 
    288     for (ring_idx = CMICX_MIIM_RING_INDEX_START; ring_idx <= ring_idx_end; ring_idx++) {
    289         soc_cmicx_miim_divider_set_ring(unit, ring_idx, int_divider, ext_divider, out_delay);
    290     }
    291 
    292     return SOC_E_NONE;
    293 }
    294 
    295 /** see .h file   */
    296 int
    297 soc_cmicx_miim_operation(int unit, int is_write, int clause, int int_delay, int ext_delay,
    298                             uint32 phy_id, uint32 phy_reg_addr, uint16 *phy_data)
    299 {
    300     uint32 reg_val = 0, internal_select, real_phy_id, real_bus_id, is_done, is_error;
    301     uint32 devad = 0;
    302     soc_timeout_t to;
    303     int clause45 = 0;
    304     uint32 cycle_type = 0, phy_devad = 0;
    305     int current_out_delay = 0, new_out_delay = 0;
    306     SOC_INIT_FUNC_DEFS;
    307 
    308 #if (defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT))
    309     if (SOC_IS_DNX(unit) || SOC_IS_DNXF(unit)) {
    310         if (is_write && dnxc_ha_is_access_disabled(unit,DNXC_HA_ALLOW_SCHAN))
    311         {
    312             LOG_WARN(BSL_LS_SOC_MIIM,
    313                 (BSL_META_U(unit,
    314                                 "soc_cmicx_miim_operation: ERROR, It is not currently allowed to modify HW\n")));
    315             _SOC_IF_ERR_EXIT(SOC_E_FAIL);
    316         }
    317     }
    318 #endif
    319 
    320 #if defined(BCM_DNX_SUPPORT) && defined(DNX_ERR_RECOVERY_VALIDATION)
    321     
    322     if (SOC_IS_DNX(unit)) {
    323         if (is_write && !DNX_ERR_RECOVERY_HW_ACCESS_IS_VALID(unit))
    324         {
    325             LOG_WARN(BSL_LS_SOC_MIIM,
    326                 (BSL_META_U(unit,
    327                                 "soc_cmicx_miim_operation: ERROR, Invalid error recovery hw access\n")));
    328             _SOC_IF_ERR_EXIT(SOC_E_FAIL);
    329         }
    330     }
    331 #endif
    332 
    333     clause45 = (SOC_CLAUSE_45 == clause);
    334 
    335     /* parse phy_id to bus, phy, and internal indication
    336     *   phy_id encoding:
    337     *       bit7, 1: internal MDIO bus, 0: external MDIO bus
    338     *       bit9,8,6,5, mdio bus number
    339     *       bit4-0,   mdio addresses
    340     */
    341     internal_select = (phy_id & 0x80) ? 1 : 0;
    342     real_phy_id = phy_id & ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK);
    343     real_phy_id &= ~(0x80); /*clear internal / external bit*/
    344     real_bus_id = PHY_ID_BUS_NUM(phy_id);
    345 
    346     MIIM_LOCK(unit);
    347 
    348     /**
    349      * Workaround to artificially support different divider delays for INTERNAL and EXTERNAL DIVISORs
    350      */
    351     _SOC_IF_ERR_EXIT(soc_cmicx_miim_divider_ring_delay_get(unit, real_bus_id, &current_out_delay));
    352     new_out_delay = internal_select ? int_delay : ext_delay;
    353     /**
    354      * Change only if new and old are different and if an actual valid delay value was rovided
    355      */
    356     if(new_out_delay != current_out_delay && new_out_delay != MIIM_INTERNAL_EXTERNAL_DELAY_INVALID) {
    357         _SOC_IF_ERR_EXIT(soc_cmicx_miim_divider_ring_delay_set(unit, real_bus_id, new_out_delay));
    358     }
    359 
    360     /* preper transaction data */
    361     /* _SOC_IF_ERR_EXIT(READ_MIIM_CH0_ADDRESSr(unit, &reg_val)); */
    362      _SOC_IF_ERR_EXIT(soc_iproc_getreg(unit, soc_reg_addr(unit, MIIM_CH0_ADDRESSr, REG_PORT_ANY, 0), &reg_val));
    363     soc_reg_field_set(unit, MIIM_CH0_ADDRESSr, &reg_val, PHY_IDf, real_phy_id);
    364 
    365     if (clause45) {
    366         /* cleanup of devad flags */
    367         devad = SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr) & 0x1f;
    368 
    369         soc_reg_field_set(unit, MIIM_CH0_ADDRESSr, &reg_val, CLAUSE_45_REG_ADRRf, SOC_PHY_CLAUSE45_REGAD(phy_reg_addr));
    370 
    371         /* IPROC 15 and higher devices */
    372         if (soc_is_miim_12r(unit)) {
    373             soc_reg_field_set(unit, MIIM_CH0_ADDRESSr, &reg_val, CLAUSE_22_REGADRR_OR_45_DTYPEf, devad);
    374         } else {
    375             soc_reg_field_set(unit, MIIM_CH0_ADDRESSr, &reg_val, CLAUSE_45_DTYPEf, devad);
    376         }
    377     } else {
    378         /* IPROC 15 and higher devices */
    379         if (soc_is_miim_12r(unit)) {
    380             soc_reg_field_set(unit, MIIM_CH0_ADDRESSr, &reg_val, CLAUSE_22_REGADRR_OR_45_DTYPEf, (phy_reg_addr & 0x1f));
    381         } else {
    382             soc_reg_field_set(unit, MIIM_CH0_ADDRESSr, &reg_val, CLAUSE_22_REG_ADRRf, (phy_reg_addr & 0x1f));
    383         }
    384     }
    385     /* _SOC_IF_ERR_EXIT(WRITE_MIIM_CH0_ADDRESSr(unit, reg_val)); */
    386     _SOC_IF_ERR_EXIT(soc_iproc_setreg(unit, soc_reg_addr(unit, MIIM_CH0_ADDRESSr, REG_PORT_ANY, 0), reg_val));
    387 
    388     if (clause45){
    389         LOG_VERBOSE(BSL_LS_SOC_MIIM,
    390                  (BSL_META_U(unit,
    391                              "soc_cmicx_miim_operation cl45 %s: "
    392                              "(id=0x%02x readr=0x%x dtype=0x%x data=0x%04x clause45=%d, real_phy_id=%d, real_bus_id=%d)\n"),
    393                   is_write ? "write" : "read ", phy_id, SOC_PHY_CLAUSE45_REGAD(phy_reg_addr), SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr),
    394                   *phy_data, clause45, real_phy_id,real_bus_id));
    395     } else {
    396         LOG_VERBOSE(BSL_LS_SOC_MIIM,
    397                  (BSL_META_U(unit,
    398                              "soc_cmicx_miim_operation cl22 %s: "
    399                              "(id=0x%02x addr=0x%02x data=0x%04x clause45=%d, real_phy_id=%d, real_bus_id=%d)\n"),
    400                   is_write ? "write" : "read ", phy_id, phy_reg_addr, *phy_data, clause45,real_phy_id,real_bus_id));
    401     }
    402 
    403     /* _SOC_IF_ERR_EXIT(READ_MIIM_CH0_PARAMSr(unit, &reg_val)); */
    404     _SOC_IF_ERR_EXIT(soc_iproc_getreg(unit, soc_reg_addr(unit, MIIM_CH0_PARAMSr, REG_PORT_ANY, 0), &reg_val));
    405     soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, SEL_INT_PHYf, internal_select);
    406     soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, RING_MAPf, (1 << real_bus_id));
    407 
    408     /* Only applicable for iProc 14 devices */
    409     if (!soc_is_miim_12r(unit)) {
    410         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, SEL_CL45f, clause45);
    411         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, RD_ENf, is_write ? 0 : 1);
    412         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, WR_ENf, is_write ? 1 : 0);
    413     }
    414 
    415     /*
    416      * Configure correct MDIO CYCLE type depending on if this data only mode
    417      * without corresponding address cycle for MDIO transcation.
    418      */
    419     phy_devad = phy_reg_addr >> 16;
    420     cycle_type = soc_cmicx_miim_cycle_type_get(unit, is_write, clause45, phy_devad);
    421 
    422     /* IPROC 15 and higher devices */
    423     if (soc_is_miim_12r(unit)) {
    424         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, MDIO_OP_TYPEf, cycle_type);
    425     } else {
    426         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, MDIO_CYCLEf, cycle_type);
    427     }
    428 
    429     if(is_write) {
    430         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, PHY_WR_DATAf, *phy_data);
    431     } else {
    432         soc_reg_field_set(unit, MIIM_CH0_PARAMSr, &reg_val, PHY_WR_DATAf, 0x0);
    433     }
    434 
    435     /* _SOC_IF_ERR_EXIT(WRITE_MIIM_CH0_PARAMSr(unit, reg_val)); */
    436     _SOC_IF_ERR_EXIT(soc_iproc_setreg(unit, soc_reg_addr(unit, MIIM_CH0_PARAMSr, REG_PORT_ANY, 0), reg_val));
    437 
    438     /* start transaction */
    439     reg_val = 0;
    440     soc_reg_field_set(unit, MIIM_CH0_CONTROLr, &reg_val, STARTf, 0x1);
    441     /* _SOC_IF_ERR_EXIT(WRITE_MIIM_CH0_CONTROLr(unit, reg_val)); */
    442     _SOC_IF_ERR_EXIT(soc_iproc_setreg(unit, soc_reg_addr(unit, MIIM_CH0_CONTROLr, REG_PORT_ANY, 0), reg_val));
    443 
    444     /* poll for DONE bit*/
    445     soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 2500);
    446 
    447     while (1){
    448         /* _SOC_IF_ERR_EXIT(READ_MIIM_CH0_STATUSr(unit, &reg_val)); */
    449         _SOC_IF_ERR_EXIT(soc_iproc_getreg(unit, soc_reg_addr(unit, MIIM_CH0_STATUSr, REG_PORT_ANY, 0), &reg_val));
    450         is_done = soc_reg_field_get(unit, MIIM_CH0_STATUSr, reg_val, DONEf);
    451         if (is_done) {
    452             break; /* MIIM operation is done */
    453         }
    454 
    455         if (soc_timeout_check(&to)) {
    456             LOG_ERROR(BSL_LS_SOC_MIIM,
    457                       (BSL_META_U(unit,
    458                                   "MiimTimeOut: %s, "
    459                                   "timeout (id=0x%02x addr=0x%02x)\n"),
    460                                     is_write ? "write" : "read" ,
    461                                     phy_id, phy_reg_addr));
    462             _SOC_IF_ERR_EXIT(SOC_E_TIMEOUT);
    463         }
    464     }
    465 
    466     LOG_DEBUG(BSL_LS_SOC_MIIM,
    467                 (BSL_META_U(unit,
    468                             "  Done in %d polls\n"), to.polls));
    469 
    470     /* check for transaction error */
    471     is_error = soc_reg_field_get(unit, MIIM_CH0_STATUSr, reg_val, ERRORf);
    472     if (is_error) {
    473         LOG_ERROR(BSL_LS_SOC_MIIM,
    474                     (BSL_META_U(unit,
    475                                 "  MDIO transaction Error\n")));
    476         _SOC_IF_ERR_EXIT(SOC_E_FAIL);
    477     }
    478 
    479     /* in case of read - get data */
    480     if (!is_write) {
    481         *phy_data = (uint16)soc_reg_field_get(unit, MIIM_CH0_STATUSr, reg_val, PHY_RD_DATAf);
    482         LOG_VERBOSE(BSL_LS_SOC_MIIM,
    483                      (BSL_META_U(unit,
    484                                  "soc_cmicx_miim_operation read data: %d \n"),*phy_data));
    485     }
    486 
    487     /* cleanup */
    488     reg_val = 0;
    489     soc_reg_field_set(unit, MIIM_CH0_CONTROLr, &reg_val, STARTf, 0x0);
    490     /* _SOC_IF_ERR_EXIT(WRITE_MIIM_CH0_CONTROLr(unit, reg_val)); */
    491     _SOC_IF_ERR_EXIT(soc_iproc_setreg(unit, soc_reg_addr(unit, MIIM_CH0_CONTROLr, REG_PORT_ANY, 0), reg_val));
    492 
    493 exit:
    494     /* in case we failed - try to cleanup */
    495     if (SOC_FUNC_ERROR) {
    496         reg_val = 0;
    497         soc_reg_field_set(unit, MIIM_CH0_CONTROLr, &reg_val, STARTf, 0x0);
    498         /* WRITE_MIIM_CH0_CONTROLr(unit, reg_val); */ /* no need to catch error in case of failrue */
    499         _SOC_IF_ERR_EXIT(soc_iproc_setreg(unit, soc_reg_addr(unit, MIIM_CH0_CONTROLr, REG_PORT_ANY, 0), reg_val));
    500     }
    501 
    502     /* Release linkscan pause and MIIM lock */
    503     MIIM_UNLOCK(unit);
    504 
    505     SOC_FUNC_RETURN;
    506 }
    507 
    508 #endif /* BCM_CMICX_SUPPORT  */