1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 /* Copyright 2019 NXP */ 3 4 #include <linux/fsl/enetc_mdio.h> 5 #include <linux/mdio.h> 6 #include <linux/of_mdio.h> 7 #include <linux/iopoll.h> 8 #include <linux/of.h> 9 10 #include "enetc_pf.h" 11 12 #define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */ 13 #define ENETC_MDIO_CTL 0x4 /* MDIO control */ 14 #define ENETC_MDIO_DATA 0x8 /* MDIO data */ 15 #define ENETC_MDIO_ADDR 0xc /* MDIO address */ 16 17 #define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8) 18 #define MDIO_CFG_BSY BIT(0) 19 #define MDIO_CFG_RD_ER BIT(1) 20 #define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2)) 21 #define MDIO_CFG_ENC45 BIT(6) 22 /* external MDIO only - driven on neg MDC edge */ 23 #define MDIO_CFG_NEG BIT(23) 24 25 #define ENETC_EMDIO_CFG \ 26 (MDIO_CFG_HOLD(2) | \ 27 MDIO_CFG_CLKDIV(258) | \ 28 MDIO_CFG_NEG) 29 30 #define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f) 31 #define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5) 32 #define MDIO_CTL_READ BIT(15) 33 34 static inline u32 enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off) 35 { 36 return enetc_port_rd_mdio(mdio_priv->hw, mdio_priv->mdio_base + off); 37 } 38 39 static inline void enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off, 40 u32 val) 41 { 42 enetc_port_wr_mdio(mdio_priv->hw, mdio_priv->mdio_base + off, val); 43 } 44 45 static bool enetc_mdio_is_busy(struct enetc_mdio_priv *mdio_priv) 46 { 47 return enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_BSY; 48 } 49 50 static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv) 51 { 52 bool is_busy; 53 54 return readx_poll_timeout(enetc_mdio_is_busy, mdio_priv, 55 is_busy, !is_busy, 10, 10 * 1000); 56 } 57 58 int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, 59 u16 value) 60 { 61 struct enetc_mdio_priv *mdio_priv = bus->priv; 62 u32 mdio_ctl, mdio_cfg; 63 u16 dev_addr; 64 int ret; 65 66 mdio_cfg = ENETC_EMDIO_CFG; 67 dev_addr = regnum & 0x1f; 68 mdio_cfg &= ~MDIO_CFG_ENC45; 69 70 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 71 72 ret = enetc_mdio_wait_complete(mdio_priv); 73 if (ret) 74 return ret; 75 76 /* set port and dev addr */ 77 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 78 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 79 80 /* write the value */ 81 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); 82 83 ret = enetc_mdio_wait_complete(mdio_priv); 84 if (ret) 85 return ret; 86 87 return 0; 88 } 89 EXPORT_SYMBOL_GPL(enetc_mdio_write_c22); 90 91 int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, 92 int regnum, u16 value) 93 { 94 struct enetc_mdio_priv *mdio_priv = bus->priv; 95 u32 mdio_ctl, mdio_cfg; 96 int ret; 97 98 mdio_cfg = ENETC_EMDIO_CFG; 99 mdio_cfg |= MDIO_CFG_ENC45; 100 101 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 102 103 ret = enetc_mdio_wait_complete(mdio_priv); 104 if (ret) 105 return ret; 106 107 /* set port and dev addr */ 108 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 109 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 110 111 /* set the register address */ 112 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 113 114 ret = enetc_mdio_wait_complete(mdio_priv); 115 if (ret) 116 return ret; 117 118 /* write the value */ 119 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); 120 121 ret = enetc_mdio_wait_complete(mdio_priv); 122 if (ret) 123 return ret; 124 125 return 0; 126 } 127 EXPORT_SYMBOL_GPL(enetc_mdio_write_c45); 128 129 int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) 130 { 131 struct enetc_mdio_priv *mdio_priv = bus->priv; 132 u32 mdio_ctl, mdio_cfg; 133 u16 dev_addr, value; 134 int ret; 135 136 mdio_cfg = ENETC_EMDIO_CFG; 137 dev_addr = regnum & 0x1f; 138 mdio_cfg &= ~MDIO_CFG_ENC45; 139 140 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 141 142 ret = enetc_mdio_wait_complete(mdio_priv); 143 if (ret) 144 return ret; 145 146 /* set port and device addr */ 147 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 148 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 149 150 /* initiate the read */ 151 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); 152 153 ret = enetc_mdio_wait_complete(mdio_priv); 154 if (ret) 155 return ret; 156 157 /* return all Fs if nothing was there */ 158 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { 159 dev_dbg(&bus->dev, 160 "Error while reading PHY%d reg at %d.%d\n", 161 phy_id, dev_addr, regnum); 162 return 0xffff; 163 } 164 165 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; 166 167 return value; 168 } 169 EXPORT_SYMBOL_GPL(enetc_mdio_read_c22); 170 171 int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, 172 int regnum) 173 { 174 struct enetc_mdio_priv *mdio_priv = bus->priv; 175 u32 mdio_ctl, mdio_cfg; 176 u16 value; 177 int ret; 178 179 mdio_cfg = ENETC_EMDIO_CFG; 180 mdio_cfg |= MDIO_CFG_ENC45; 181 182 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 183 184 ret = enetc_mdio_wait_complete(mdio_priv); 185 if (ret) 186 return ret; 187 188 /* set port and device addr */ 189 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 190 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 191 192 /* set the register address */ 193 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 194 195 ret = enetc_mdio_wait_complete(mdio_priv); 196 if (ret) 197 return ret; 198 199 /* initiate the read */ 200 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); 201 202 ret = enetc_mdio_wait_complete(mdio_priv); 203 if (ret) 204 return ret; 205 206 /* return all Fs if nothing was there */ 207 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { 208 dev_dbg(&bus->dev, 209 "Error while reading PHY%d reg at %d.%d\n", 210 phy_id, dev_addr, regnum); 211 return 0xffff; 212 } 213 214 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; 215 216 return value; 217 } 218 EXPORT_SYMBOL_GPL(enetc_mdio_read_c45); 219 220 struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) 221 { 222 struct enetc_hw *hw; 223 224 hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 225 if (!hw) 226 return ERR_PTR(-ENOMEM); 227 228 hw->port = port_regs; 229 230 return hw; 231 } 232 EXPORT_SYMBOL_GPL(enetc_hw_alloc); 233 234 /* Lock for MDIO access errata on LS1028A */ 235 DEFINE_RWLOCK(enetc_mdio_lock); 236 EXPORT_SYMBOL_GPL(enetc_mdio_lock); 237