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