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

shbde_mdio.c (5166B)


      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 
      8 #include <shbde_mdio.h>
      9 
     10 /* iProc MDIO register offset */
     11 #define MII_MGMT_CTRL                       0x0
     12 #define MII_MGMT_CMD_DATA                   0x4
     13 
     14 /* iProc MII register with fields definition */
     15 #define MII_MGMT_CTRLr_MDCDIVf_SHFT         0
     16 #define MII_MGMT_CTRLr_MDCDIVf_MASK         0x7f
     17 #define MII_MGMT_CTRLr_BSYf_SHFT            8
     18 #define MII_MGMT_CTRLr_BSYf_MASK            0x1
     19 
     20 #define MII_MGMT_CMD_DATAr_DATAf_SHFT       0
     21 #define MII_MGMT_CMD_DATAr_DATAf_MASK       0xffff
     22 #define MII_MGMT_CMD_DATAr_TAf_SHFT         16
     23 #define MII_MGMT_CMD_DATAr_TAf_MASK         0x3
     24 #define MII_MGMT_CMD_DATAr_RAf_SHFT         18
     25 #define MII_MGMT_CMD_DATAr_RAf_MASK         0x1f
     26 #define MII_MGMT_CMD_DATAr_PAf_SHFT         23
     27 #define MII_MGMT_CMD_DATAr_PAf_MASK         0x1f
     28 #define MII_MGMT_CMD_DATAr_OPf_SHFT         28
     29 #define MII_MGMT_CMD_DATAr_OPf_MASK         0x3
     30 #define MII_MGMT_CMD_DATAr_SBf_SHFT         30
     31 #define MII_MGMT_CMD_DATAr_SBf_MASK         0x3
     32 
     33 /* Register field value set/get */
     34 #define REG_FIELD_SET(_r, _f, _r_val, _f_val) \
     35         _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \
     36                  (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT)
     37 #define REG_FIELD_GET(_r, _f, _r_val) \
     38         (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK)
     39 
     40 #define LOG_OUT(_shbde, _lvl, _str, _prm)             \
     41     if ((_shbde)->log_func) {                         \
     42         (_shbde)->log_func(_lvl, _str, _prm);         \
     43     }
     44 #define LOG_ERR(_shbde, _str, _prm)     LOG_OUT(_shbde, SHBDE_ERR, _str, _prm)
     45 #define LOG_WARN(_shbde, _str, _prm)    LOG_OUT(_shbde, SHBDE_WARN, _str, _prm)
     46 #define LOG_DBG(_shbde, _str, _prm)     LOG_OUT(_shbde, SHBDE_DBG, _str, _prm)
     47 
     48 static unsigned int
     49 mdio32_read(shbde_mdio_ctrl_t *smc, unsigned int offset)
     50 {
     51     if (!smc || !smc->io32_read) {
     52         return 0;
     53     }
     54     return smc->io32_read(smc->shbde, smc->regs, smc->base_addr + offset);
     55 }
     56 
     57 static void
     58 mdio32_write(shbde_mdio_ctrl_t *smc, unsigned int offset, unsigned int data)
     59 {
     60     if (!smc || !smc->io32_read) {
     61         return;
     62     }
     63     smc->io32_write(smc->shbde, smc->regs, smc->base_addr + offset, data);
     64 }
     65 
     66 static void
     67 wait_usec(shbde_mdio_ctrl_t *smc, int usec)
     68 {
     69     shbde_hal_t *shbde = smc->shbde;
     70 
     71     if (shbde && shbde->usleep) {
     72         shbde->usleep(usec);
     73     } else {
     74         int idx;
     75         volatile int count;
     76         for (idx = 0; idx < usec; idx++) {
     77             for (count = 0; count < 100; count++);
     78         }
     79     }
     80 }
     81 
     82 static int
     83 iproc_mdio_wait_for_busy(shbde_mdio_ctrl_t *smc)
     84 {
     85     int mii_busy;
     86     unsigned int reg_val;
     87     int count = 1000;
     88 
     89     /* Wait until MII is not busy */
     90     do {
     91         reg_val = mdio32_read(smc, MII_MGMT_CTRL);
     92         mii_busy = REG_FIELD_GET(MII_MGMT_CTRLr, BSYf, reg_val);
     93         if (!mii_busy) {
     94             break;
     95         }
     96         wait_usec(smc, 10);
     97         count --;
     98     } while (count > 0);
     99 
    100     return mii_busy;
    101 }
    102 
    103 int
    104 shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc)
    105 {
    106     shbde_hal_t *shbde = smc->shbde;
    107     unsigned int reg_val = 0;
    108 
    109     /* Enable the iProc internal MDIO interface */
    110     REG_FIELD_SET(MII_MGMT_CTRLr, MDCDIVf, reg_val, 0x7f);
    111     mdio32_write(smc, MII_MGMT_CTRL, reg_val);
    112 
    113     if (shbde && !shbde->usleep) {
    114         LOG_DBG(shbde, "shbde_mdio: no registration of usleep vector", 0);
    115     }
    116 
    117     wait_usec(smc, 100);
    118 
    119     return 0;
    120 }
    121 
    122 int
    123 shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
    124                       unsigned int reg, unsigned int *val)
    125 {
    126     unsigned int reg_val = 0;
    127 
    128     REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
    129     REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
    130     REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x2);
    131     REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
    132     REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
    133     mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
    134 
    135     if (iproc_mdio_wait_for_busy(smc)) {
    136         *val = 0;
    137         LOG_DBG(smc->shbde, "shbde_iproc_mdio_read busy", reg);
    138         return -1;
    139     }
    140 
    141     reg_val = mdio32_read(smc, MII_MGMT_CMD_DATA);
    142     *val = REG_FIELD_GET(MII_MGMT_CMD_DATAr, DATAf, reg_val);
    143 
    144     return 0;
    145 }
    146 
    147 int
    148 shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
    149                        unsigned int reg, unsigned int val)
    150 {
    151     unsigned int reg_val = 0;
    152 
    153     REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
    154     REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
    155     REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x1);
    156     REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
    157     REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
    158     REG_FIELD_SET(MII_MGMT_CMD_DATAr, DATAf, reg_val, val);
    159     mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
    160 
    161     if (iproc_mdio_wait_for_busy(smc)) {
    162         LOG_DBG(smc->shbde, "shbde_iproc_mdio_write busy", reg);
    163         return -1;
    164     }
    165 
    166     /* Wait for some time for the write to take effect */
    167     wait_usec(smc, 100);
    168 
    169     return 0;
    170 }
    171