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 (5672B)


      1 /*
      2  * Copyright 2017 Broadcom
      3  * 
      4  * This program is free software; you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License, version 2, as
      6  * published by the Free Software Foundation (the "GPL").
      7  * 
      8  * This program is distributed in the hope that it will be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     11  * General Public License version 2 (GPLv2) for more details.
     12  * 
     13  * You should have received a copy of the GNU General Public License
     14  * version 2 (GPLv2) along with this source code.
     15  */
     16 /*
     17  * $Id: $
     18  * $Copyright: (c) 2015 Broadcom Corp.
     19  * All Rights Reserved.$
     20  *
     21  */
     22 
     23 #include <shbde_mdio.h>
     24 
     25 /* iProc MDIO register offset */
     26 #define MII_MGMT_CTRL                       0x0
     27 #define MII_MGMT_CMD_DATA                   0x4
     28 
     29 /* iProc MII register with fields definition */
     30 #define MII_MGMT_CTRLr_MDCDIVf_SHFT         0
     31 #define MII_MGMT_CTRLr_MDCDIVf_MASK         0x7f
     32 #define MII_MGMT_CTRLr_BSYf_SHFT            8
     33 #define MII_MGMT_CTRLr_BSYf_MASK            0x1
     34 
     35 #define MII_MGMT_CMD_DATAr_DATAf_SHFT       0
     36 #define MII_MGMT_CMD_DATAr_DATAf_MASK       0xffff
     37 #define MII_MGMT_CMD_DATAr_TAf_SHFT         16
     38 #define MII_MGMT_CMD_DATAr_TAf_MASK         0x3
     39 #define MII_MGMT_CMD_DATAr_RAf_SHFT         18
     40 #define MII_MGMT_CMD_DATAr_RAf_MASK         0x1f
     41 #define MII_MGMT_CMD_DATAr_PAf_SHFT         23
     42 #define MII_MGMT_CMD_DATAr_PAf_MASK         0x1f
     43 #define MII_MGMT_CMD_DATAr_OPf_SHFT         28
     44 #define MII_MGMT_CMD_DATAr_OPf_MASK         0x3
     45 #define MII_MGMT_CMD_DATAr_SBf_SHFT         30
     46 #define MII_MGMT_CMD_DATAr_SBf_MASK         0x3
     47 
     48 /* Register field value set/get */
     49 #define REG_FIELD_SET(_r, _f, _r_val, _f_val) \
     50         _r_val = ((_r_val) & ~(_r##_##_f##_MASK << _r##_##_f##_SHFT)) | \
     51                  (((_f_val) & _r##_##_f##_MASK) << _r##_##_f##_SHFT)
     52 #define REG_FIELD_GET(_r, _f, _r_val) \
     53         (((_r_val) >> _r##_##_f##_SHFT) & _r##_##_f##_MASK)
     54 
     55 #define LOG_OUT(_shbde, _lvl, _str, _prm)             \
     56     if ((_shbde)->log_func) {                         \
     57         (_shbde)->log_func(_lvl, _str, _prm);         \
     58     }
     59 #define LOG_ERR(_shbde, _str, _prm)     LOG_OUT(_shbde, SHBDE_ERR, _str, _prm)
     60 #define LOG_WARN(_shbde, _str, _prm)    LOG_OUT(_shbde, SHBDE_WARN, _str, _prm)
     61 #define LOG_DBG(_shbde, _str, _prm)     LOG_OUT(_shbde, SHBDE_DBG, _str, _prm)
     62 
     63 static unsigned int
     64 mdio32_read(shbde_mdio_ctrl_t *smc, unsigned int offset)
     65 {
     66     if (!smc || !smc->io32_read) {
     67         return 0;
     68     }
     69     return smc->io32_read(smc->shbde, smc->regs, smc->base_addr + offset);
     70 }
     71 
     72 static void
     73 mdio32_write(shbde_mdio_ctrl_t *smc, unsigned int offset, unsigned int data)
     74 {
     75     if (!smc || !smc->io32_read) {
     76         return;
     77     }
     78     smc->io32_write(smc->shbde, smc->regs, smc->base_addr + offset, data);
     79 }
     80 
     81 static void
     82 wait_usec(shbde_mdio_ctrl_t *smc, int usec)
     83 {
     84     shbde_hal_t *shbde = smc->shbde;
     85 
     86     if (shbde && shbde->usleep) {
     87         shbde->usleep(usec);
     88     } else {
     89         int idx;
     90         volatile int count;
     91         for (idx = 0; idx < usec; idx++) {
     92             for (count = 0; count < 100; count++);
     93         }
     94     }
     95 }
     96 
     97 static int
     98 iproc_mdio_wait_for_busy(shbde_mdio_ctrl_t *smc)
     99 {
    100     int mii_busy;
    101     unsigned int reg_val;
    102     int count = 1000;
    103 
    104     /* Wait until MII is not busy */
    105     do {
    106         reg_val = mdio32_read(smc, MII_MGMT_CTRL);
    107         mii_busy = REG_FIELD_GET(MII_MGMT_CTRLr, BSYf, reg_val);
    108         if (!mii_busy) {
    109             break;
    110         }
    111         wait_usec(smc, 10);
    112         count --;
    113     } while (count > 0);
    114 
    115     return mii_busy;
    116 }
    117 
    118 int
    119 shbde_iproc_mdio_init(shbde_mdio_ctrl_t *smc)
    120 {
    121     shbde_hal_t *shbde = smc->shbde;
    122     unsigned int reg_val = 0;
    123 
    124     /* Enable the iProc internal MDIO interface */
    125     REG_FIELD_SET(MII_MGMT_CTRLr, MDCDIVf, reg_val, 0x7f);
    126     mdio32_write(smc, MII_MGMT_CTRL, reg_val);
    127 
    128     if (shbde && !shbde->usleep) {
    129         LOG_DBG(shbde, "shbde_mdio: no registration of usleep vector", 0);
    130     }
    131 
    132     wait_usec(smc, 100);
    133 
    134     return 0;
    135 }
    136 
    137 int
    138 shbde_iproc_mdio_read(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
    139                       unsigned int reg, unsigned int *val)
    140 {
    141     unsigned int reg_val = 0;
    142 
    143     REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
    144     REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
    145     REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x2);
    146     REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
    147     REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
    148     mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
    149 
    150     if (iproc_mdio_wait_for_busy(smc)) {
    151         *val = 0;
    152         LOG_DBG(smc->shbde, "shbde_iproc_mdio_read busy", reg);
    153         return -1;
    154     }
    155 
    156     reg_val = mdio32_read(smc, MII_MGMT_CMD_DATA);
    157     *val = REG_FIELD_GET(MII_MGMT_CMD_DATAr, DATAf, reg_val);
    158 
    159     return 0;
    160 }
    161 
    162 int
    163 shbde_iproc_mdio_write(shbde_mdio_ctrl_t *smc, unsigned int phy_addr,
    164                        unsigned int reg, unsigned int val)
    165 {
    166     unsigned int reg_val = 0;
    167 
    168     REG_FIELD_SET(MII_MGMT_CMD_DATAr, SBf, reg_val, 0x1);
    169     REG_FIELD_SET(MII_MGMT_CMD_DATAr, TAf, reg_val, 0x2);
    170     REG_FIELD_SET(MII_MGMT_CMD_DATAr, OPf, reg_val, 0x1);
    171     REG_FIELD_SET(MII_MGMT_CMD_DATAr, PAf, reg_val, phy_addr);
    172     REG_FIELD_SET(MII_MGMT_CMD_DATAr, RAf, reg_val, reg);
    173     REG_FIELD_SET(MII_MGMT_CMD_DATAr, DATAf, reg_val, val);
    174     mdio32_write(smc, MII_MGMT_CMD_DATA, reg_val);
    175 
    176     if (iproc_mdio_wait_for_busy(smc)) {
    177         LOG_DBG(smc->shbde, "shbde_iproc_mdio_write busy", reg);
    178         return -1;
    179     }
    180 
    181     /* Wait for some time for the write to take effect */
    182     wait_usec(smc, 100);
    183 
    184     return 0;
    185 }
    186